Repository: tableau/document-api-python
Branch: master
Commit: 39d596746dc4
Files: 87
Total size: 66.0 MB
Directory structure:
gitextract_g_ptwokv/
├── .github/
│ └── workflows/
│ ├── publish-pypi.yml
│ └── python-package.yml
├── .gitignore
├── CHANGELOG.md
├── CODEOWNERS
├── CONTRIBUTORS.md
├── LICENSE
├── README.md
├── docs/
│ ├── .keep
│ ├── Gemfile
│ ├── _config.yml
│ ├── _includes/
│ │ ├── analytics.html
│ │ ├── docs_menu.html
│ │ ├── footer.html
│ │ ├── head.html
│ │ ├── header.html
│ │ └── search_form.html
│ ├── _layouts/
│ │ ├── default.html
│ │ ├── docs.html
│ │ ├── home.html
│ │ └── search.html
│ ├── css/
│ │ ├── api_ref.css
│ │ ├── extra.css
│ │ ├── github-highlight.css
│ │ └── main.css
│ ├── docs/
│ │ ├── api-ref.md
│ │ ├── contributing.md
│ │ ├── dev-guide.md
│ │ ├── index.md
│ │ └── search.md
│ ├── index.md
│ └── js/
│ ├── redirect-to-search.js
│ └── search.js
├── publish.sh
├── requirements.txt
├── samples/
│ ├── preserve-namespaces/
│ │ ├── TABLEAU_10_TWB.twb
│ │ ├── filtering.twb
│ │ └── preserve-namespaces.py
│ ├── replicate-workbook/
│ │ ├── databases.csv
│ │ ├── replicate_workbook.py
│ │ └── sample-superstore.twb
│ ├── show-fields/
│ │ ├── nested.tds
│ │ ├── new-world.tds
│ │ └── show_fields.py
│ └── show_workbook_info/
│ ├── geocoding.twbx
│ ├── show_workbook_info.py
│ └── world.tds
├── setup.cfg
├── setup.py
├── tableaudocumentapi/
│ ├── __init__.py
│ ├── connection.py
│ ├── datasource.py
│ ├── dbclass.py
│ ├── field.py
│ ├── multilookup_dict.py
│ ├── property_decorators.py
│ ├── workbook.py
│ └── xfile.py
└── test/
├── __init__.py
├── assets/
│ ├── .gitignore
│ ├── CONNECTION.xml
│ ├── Cache.twbx
│ ├── TABLEAU_10_TDS.tds
│ ├── TABLEAU_10_TDSX.tdsx
│ ├── TABLEAU_10_TWB.twb
│ ├── TABLEAU_10_TWBX.twbx
│ ├── TABLEAU_82_TWB.twb
│ ├── TABLEAU_93_TDS.tds
│ ├── TABLEAU_93_TWB.twb
│ ├── __init__.py
│ ├── datasource_test.tds
│ ├── datasource_test.twb
│ ├── empty_workbook.twb
│ ├── ephemeral_field.twb
│ ├── field_change_test.tds
│ ├── filtering.twb
│ ├── index.py
│ ├── multiple_connections.twb
│ ├── shapes_test.twb
│ └── unicode.tds
├── bvt.py
├── test_datasource.py
├── test_field.py
├── test_field_change.py
├── test_multidict.py
├── test_workbook.py
└── test_xfile.py
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/publish-pypi.yml
================================================
name: Publish to PyPi
on:
workflow_dispatch:
push:
branches: development, main
jobs:
build-n-publish:
name: Build dist files for PyPi
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: 3.13
- name: Build dist files
run: >
python -m pip install --upgrade pip && pip install -e .[build] &&
python setup.py build &&
python setup.py sdist --formats=gztar
- name: Publish distribution 📦 to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
- name: Publish distribution 📦 to PyPI
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.PYPI_API_TOKEN }}
================================================
FILE: .github/workflows/python-package.yml
================================================
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
name: Python package
on:
push:
paths-ignore:
- "docs/**"
pull_request:
branches: "*"
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Test
run: |
python -m unittest discover -v
lint:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [3.13]
steps:
- uses: actions/checkout@v2
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install pycodestyle
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Lint with pycodestyle
run: |
pycodestyle tableaudocumentapi test samples
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
Gemfile.lock
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
# Sphinx documentation
docs/_build/
# PyBuilder
target/
#Ipython Notebook
.ipynb_checkpoints
#Other things
.DS_Store
.idea
#Editor things
*.sublime-project
*.sublime-workspace
settings.json
tasks.json
#Jekyll
docs/_site
================================================
FILE: CHANGELOG.md
================================================
## 011 (November 2022)
* Remove extraneous debug print statements
## 010 (June 2022)
* Add service/schema attributes
## 091 (March 2022)
* Add attribute for hidden field
## 09 (December 2021)
* PyPI upgraded to Python3
## 08 (October 2021)
* See dashboards in a workbook
* Add shapes property
* Add custom sql
* Drop python 2, add up through 3.9
## 07 (26 May 2021)
* Fix bug in xfile that overwrote the namespace name when saving a document
## 06 (11 January 2017)
* Initial SQL and query banding support (#123)
* Fixed bug in xfiles to allow opening workbooks with external file caches (#117, #118)
* Code Cleanup (#120, #121)
* Added Py36 support (#124)
* Switched to pycodestyle from pip8 on travis runs (#124)
## 05 (01 November 2016)
* Added ability to set the port for connections (#97)
* Added ability to read and write caption for datasources (#99)
* Added documentation
## 0.4 (07 October 2016)
* Add ability to remove repository location (#86)
* Fixed bug in connection parsing when federated connections are present (#87)
* Fixed bug in UNICODE support (#80)
## 0.3 (31 August 2016)
* Added basic connection class retargeting (#65)
* Added ability to create a new connection (#69)
* Added description to the field object (#73)
* Improved Test Coverage (#62, #67)
## 0.2 (22 July 2016)
* Added support for loading twbx and tdsx files (#43, #44)
* Added Fields property to datasource (#45)
* Added Example for using the Fields Property (#51)
* Added Ability to get fields used by a specific sheet (#54)
* Code clean up and test reorganization
## 0.1 (29 June 2016)
* Initial Release to the world
================================================
FILE: CODEOWNERS
================================================
#ECCN:Open Source
#GUSINFO:Open Source,Open Source Workflow
================================================
FILE: CONTRIBUTORS.md
================================================
This project wouldn't be possible without our amazing contributors.
The following people have contributed to this project to make it possible, and we thank them for their contributions!
## Contributors
* [Charley Peng](https://github.com/chid)
* [Miguel Sánchez](https://github.com/MiguelSR)
* [Ryan Richmond](https://github.com/r-richmond)
## Core Team
* [Tyler Doyle](https://github.com/t8y8)
* [Russell Hay](https://github.com/RussTheAerialist)
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2016 Tableau
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.
================================================
FILE: README.md
================================================
# document-api-python
[](https://www.tableau.com/support-levels-it-and-developer-tools)
Document API
---------------
This repo contains Python source and example files for the Tableau Document API.
The Document API provides a useful but *unsupported* way to programmatically make updates to Tableau workbook and data source files. If you've been making changes to these file types by directly updating the XML--that is, by XML hacking--this SDK is for you :) Get help from other users on the [Tableau Community Forums](https://community.tableau.com/s/topic/0TO4T000000SF3sWAG/document-api).
Features include:
- Support for TWB, TWBX, TDE and TDSX files starting roughly back to Tableau 9.x
- Getting connection information from data sources and workbooks
- Server Name
- Username
- Database Name
- Authentication Type
- Connection Type
- Updating connection information in workbooks and data sources
- Server Name
- Username
- Database Name
- Getting Field information from data sources and workbooks
- Get all fields in a data source
- Get all fields in use by certain sheets in a workbook
- It *doesn't* support creating files from scratch, adding extracts into workbooks or data sources, or updating field information. As of 2021, this SDK no longer supports Python 2.
For Hyper files, take a look at the [Tableau Hyper API](https://help.tableau.com/current/api/hyper_api/en-us/index.html).
For more information, see the [Document API documentation](https://tableau.github.io/document-api-python)
================================================
FILE: docs/.keep
================================================
Hello docs!
================================================
FILE: docs/Gemfile
================================================
source 'https://rubygems.org'
gem 'github-pages', group: :jekyll_plugins
================================================
FILE: docs/_config.yml
================================================
# Site settings
title: Tableau Document API
email: github@tableau.com
description: Programmatically update your Tableau workbooks and data sources.
baseurl: "/document-api-python"
permalinks: pretty
defaults:
-
scope:
path: "" # Apply to all files
values:
layout: "default"
# Build settings
markdown: kramdown
highlighter: rouge
================================================
FILE: docs/_includes/analytics.html
================================================
================================================
FILE: docs/_includes/docs_menu.html
================================================
{% include header.html %}
{% include docs_menu.html %}
Loading search results...
{% include footer.html %}
================================================
FILE: docs/css/api_ref.css
================================================
<_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m' name='TestData' table='[dbo].[TestData]' type='table' />
<_.fcp.ObjectModelEncapsulateLegacy.true...relation connection='sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m' name='TestData' table='[dbo].[TestData]' type='table' />
Account Account Name130[Account Account Name][TestData]Account Account Name1stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
SPAM1SPAM19Counttrue"xml""SQL_C_DEFAULT"Account Number5[Account Number][TestData]Account Number2realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Account Number Burst Out Account130[Account Number Burst Out Account][TestData]Account Number Burst Out Account3stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Acct Name130[Acct Name][TestData]Acct Name4stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out130[Burst Out][TestData]Burst Out5stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Join130[Burst Out Join][TestData]Burst Out Join6stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Set list5[Burst Out Set list][TestData]Burst Out Set list7realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out View5[Burst Out View][TestData]Burst Out View8realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count JE Number5[Count JE Number][TestData]Count JE Number9realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Entity ID130[Entity ID][TestData]Entity ID10stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Filter5[Filter][TestData]Filter11realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Fiscal Year130[Fiscal Year][TestData]Fiscal Year12stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag11[Flag][TestData]Flag13booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag__copy_11[Flag__copy_][TestData]Flag__copy_14booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line5[FS Line][TestData]FS Line15realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line Burst Out Account130[FS Line Burst Out Account][TestData]FS Line Burst Out Account16stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Group By5[Group By][TestData]Group By17realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Image130[Image][TestData]Image18stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line5[Note Line][TestData]Note Line19realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line Burst Out Account130[Note Line Burst Out Account][TestData]Note Line Burst Out Account20stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Selection5[Selection][TestData]Selection21realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
show130[show][TestData]show22stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Show Cycle Based130[Show Cycle Based][TestData]Show Cycle Based23stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sub Class5[Sub Class][TestData]Sub Class24realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
SubClass Burst Out Account130[SubClass Burst Out Account][TestData]SubClass Burst Out Account25stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Type130[Type][TestData]Type26stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount130[Amount][TestData]Amount27stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount1130[Amount1][TestData]Amount128stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count of Amount Calculation5[Count of Amount Calculation][TestData]Count of Amount Calculation29realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records5[Number of Records][TestData]Number of Records30realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records15[Number of Records1][TestData]Number of Records131realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Burst Out5[Select Burst Out][TestData]Select Burst Out32realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Transaction Analysis view5[Select Transaction Analysis view][TestData]Select Transaction Analysis view33realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Cy5[Sum Cy][TestData]Sum Cy34realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py15[Sum Py1][TestData]Sum Py135realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py25[Sum Py2][TestData]Sum Py236realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py35[Sum Py3][TestData]Sum Py337realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py45[Sum Py4][TestData]Sum Py438realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Credits5[Total Credits][TestData]Total Credits39realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Debits5[Total Debits][TestData]Total Debits40realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
<_.fcp.ObjectModelTableType.true...column caption='TestData' datatype='table' name='[__tableau_internal_object_id__].[TestData_44D2C885FAEF453C846AC2CCD3577055]' role='measure' type='quantitative' />
<_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
<_.fcp.GroupActionAddRemove.true...add-or-remove-marks value='assign' />
Selection
([federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Calculation_88946136969252864:nk] / [federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk])
Set Result
([federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk] / [federated.1df63xu0j2dvhd1e3sooz18pbrcc].[io:BurstoutSet:nk])
[sqlserver.187oiqw1ls5tey1df9op71phda18].[none:Market:nk]
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
AtA0TWtR/x806x+pAcUBoAAAAABJRU5ErkJggg==
================================================
FILE: samples/show-fields/nested.tds
================================================
<_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy/>
<_.fcp.ObjectModelTableType.true...ObjectModelTableType/>
<_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel/>
<_.fcp.ObjectModelEncapsulateLegacy.false...relation connection="sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m" name="TestData" table="[dbo].[TestData]" type="table"/>
<_.fcp.ObjectModelEncapsulateLegacy.true...relation connection="sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m" name="TestData" table="[dbo].[TestData]" type="table"/>
Account Account Name130[Account Account Name][TestData]Account Account Name1stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Account Number5[Account Number][TestData]Account Number2realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Account Number Burst Out Account130[Account Number Burst Out Account][TestData]Account Number Burst Out Account3stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Acct Name130[Acct Name][TestData]Acct Name4stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out130[Burst Out][TestData]Burst Out5stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Join130[Burst Out Join][TestData]Burst Out Join6stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Set list5[Burst Out Set list][TestData]Burst Out Set list7realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out View5[Burst Out View][TestData]Burst Out View8realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count JE Number5[Count JE Number][TestData]Count JE Number9realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Entity ID130[Entity ID][TestData]Entity ID10stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Filter5[Filter][TestData]Filter11realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Fiscal Year130[Fiscal Year][TestData]Fiscal Year12stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag11[Flag][TestData]Flag13booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag__copy_11[Flag__copy_][TestData]Flag__copy_14booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line5[FS Line][TestData]FS Line15realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line Burst Out Account130[FS Line Burst Out Account][TestData]FS Line Burst Out Account16stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Group By5[Group By][TestData]Group By17realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Image130[Image][TestData]Image18stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line5[Note Line][TestData]Note Line19realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line Burst Out Account130[Note Line Burst Out Account][TestData]Note Line Burst Out Account20stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Selection5[Selection][TestData]Selection21realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
show130[show][TestData]show22stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Show Cycle Based130[Show Cycle Based][TestData]Show Cycle Based23stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sub Class5[Sub Class][TestData]Sub Class24realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
SubClass Burst Out Account130[SubClass Burst Out Account][TestData]SubClass Burst Out Account25stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Type130[Type][TestData]Type26stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount130[Amount][TestData]Amount27stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount1130[Amount1][TestData]Amount128stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count of Amount Calculation5[Count of Amount Calculation][TestData]Count of Amount Calculation29realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records5[Number of Records][TestData]Number of Records30realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records15[Number of Records1][TestData]Number of Records131realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Burst Out5[Select Burst Out][TestData]Select Burst Out32realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Transaction Analysis view5[Select Transaction Analysis view][TestData]Select Transaction Analysis view33realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Cy5[Sum Cy][TestData]Sum Cy34realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py15[Sum Py1][TestData]Sum Py135realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py25[Sum Py2][TestData]Sum Py236realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py35[Sum Py3][TestData]Sum Py337realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py45[Sum Py4][TestData]Sum Py438realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Credits5[Total Credits][TestData]Total Credits39realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Debits5[Total Debits][TestData]Total Debits40realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
<_.fcp.ObjectModelTableType.true...column caption="TestData" datatype="table" name="[__tableau_internal_object_id__].[TestData_44D2C885FAEF453C846AC2CCD3577055]" role="measure" type="quantitative"/>
<_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
================================================
FILE: samples/show-fields/new-world.tds
================================================
<_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy />
<_.fcp.ObjectModelTableType.true...ObjectModelTableType />
<_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel />
<_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='World Indicatorsleaf' name='Extract' table='[Extract].[Extract]' type='table' />
<_.fcp.ObjectModelEncapsulateLegacy.true...relation connection='World Indicatorsleaf' name='Extract' table='[Extract].[Extract]' type='table' />
Birth Rate5[Birth Rate][Extract]Birth Rate0English$realSum48true0.00700000000000000010.052999999999999999true"array"true83"asc"1"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Business Tax Rate5[Business Tax Rate][Extract]Business Tax Rate1English$realSum448true0.0820000000000000033.391true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
CO2 Emissions3[CO2 Emissions][Extract]CO2 Emissions2English$integerSum1744true782868924"sint32"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Country129[Country][Extract]Country3English$stringCount20811073741823false"Afghanistan""Zimbabwe""en_US_CI"true"heap"true42949672922"asc"2"str"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Days to Start Business2[Days to Start Business][Extract]Days to Start Business4English$integerSum127true1694true"array"true21"sint16"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Ease of Business2[Ease of Business][Extract]Ease of Business5English$integerSum186true1189true"array"true21"sint16"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Energy Usage3[Energy Usage][Extract]Energy Usage6English$integerSum1722true827277284"sint32"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
GDP20[GDP][Extract]GDP7English$integerSum2495true6310127221474836478"sint64"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Health Exp % GDP5[Health Exp % GDP][Extract]Health Exp % GDP8English$realSum146true0.00800000000000000020.22500000000000001true"array"true81"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Health Exp/Capita2[Health Exp/Capita][Extract]Health Exp/Capita9English$integerSum1070true299082"sint16"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Hours to do Tax2[Hours to do Tax][Extract]Hours to do Tax10English$integerSum281true1226002"sint16"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Infant Mortality Rate5[Infant Mortality Rate][Extract]Infant Mortality Rate11English$realSum130true0.0020.14099999999999999true"array"true81"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Internet Usage5[Internet Usage][Extract]Internet Usage12English$realSum709true0.00.96199999999999997true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Lending Interest5[Lending Interest][Extract]Lending Interest13English$realSum352true0.00500000000000000014.9649999999999999true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Life Expectancy Female16[Life Expectancy Female][Extract]Life Expectancy Female14English$integerSum50true39871"sint8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Life Expectancy Male16[Life Expectancy Male][Extract]Life Expectancy Male15English$integerSum48true37881"sint8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Mobile Phone Usage5[Mobile Phone Usage][Extract]Mobile Phone Usage16English$realSum1179true0.02.8980000000000001true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Number of Records16[Number of Records][Extract]Number of Records17integerSum1false11"asc"1"sint8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Population 0-145[Population 0-14][Extract]Population 0-1418English$realSum377true0.117999999999999990.5true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Population 15-645[Population 15-64][Extract]Population 15-6419English$realSum299true0.473999999999999980.85799999999999998true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Population 65+5[Population 65+][Extract]Population 65+20English$realSum209true0.00300000000000000010.24399999999999999true"array"true81"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Population Total3[Population Total][Extract]Population Total21English$integerSum2699false1887613506950004"sint32"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Population Urban5[Population Urban][Extract]Population Urban22English$realSum823true0.0820000000000000031.0true"array"true82"double"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Region129[Region][Extract]Region23English$stringCount611073741823false"Africa""The Americas""en_US_CI"true"heap"true42949672921"asc"1"str"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Tourism Inbound20[Tourism Inbound][Extract]Tourism Inbound24English$integerSum1651true7000002147483647true"array"true82"sint64"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Tourism Outbound20[Tourism Outbound][Extract]Tourism Outbound25English$integerSum1458true2000002147483647true"array"true82"sint64"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
Year133[Year][Extract]Year26English$dateYear13false#2000-12-01##2012-12-01#true"array"true"asc"40"asc"1"date"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Migrated Data]
% of population% of Commercial profitKilotonnes of oil equivalentTime required to start a business1=EaseKilotonnesGross domestic product Healthcare expenditure as % of GDPHealthcare expenditure per capitaTime to prepare and pay taxes for business% of PopulationPer CapitaA bank rate that meets private sectors' needs.Years a newborn would live if prevailing patterns are the sameYears a newborn would live if prevailing patterns are the samePer Capita% of population% of population% of populationTotal number of people in a country% of populationIncome from inbound tourismExpenditure for outbound tourism
<_.fcp.ObjectModelTableType.true...column caption='Migrated Data' datatype='table' name='[__tableau_internal_object_id__].[Migrated Data]' role='measure' type='quantitative' />
<_.fcp.SchemaViewerObjectModel.false...folder name='Business' role='measures'>
<_.fcp.SchemaViewerObjectModel.false...folder name='Development' role='measures'>
<_.fcp.SchemaViewerObjectModel.false...folder name='Health' role='measures'>
<_.fcp.SchemaViewerObjectModel.false...folder name='Population' role='measures'>
<_.fcp.SchemaViewerObjectModel.true...folders-common>
<_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
================================================
FILE: samples/show-fields/show_fields.py
================================================
############################################################
# Step 1) Use Datasource object from the Document API
############################################################
from tableaudocumentapi import Datasource
############################################################
# Step 2) Open the .tds we want to inspect
############################################################
datasources = [Datasource.from_file('world.tds'), Datasource.from_file('nested.tds')]
for sourceTDS in datasources:
############################################################
# Step 3) Print out all of the fields and what type they are
############################################################
print('----------------------------------------------------------')
print('-- Info for our .tds:')
print('-- name:\t{0}'.format(sourceTDS.name))
print('-- version:\t{0}'.format(sourceTDS.version))
print('----------------------------------------------------------')
print('--- {} total fields in this datasource'.format(len(sourceTDS.fields)))
print('----------------------------------------------------------')
for count, field in enumerate(sourceTDS.fields.values()):
blank_line = False
if field.calculation:
print('{:>4}: field named `{}` is a `{}`'.format(count+1, field.name, field.datatype))
print(' field id, caption, calculation: `{}`, `{}`, `{}`'.format(field.id, field.caption,
field.calculation))
blank_line = True
if field.default_aggregation:
print('{:>4}: `{}` is a `{}`, default aggregation is `{}`'.format(count+1, field.name, field.datatype,
field.default_aggregation))
if field.description:
print('{:>4}: `{}` is a `{}`, description is `{}`'.format(count+1, field.name, field.datatype,
field.description))
if blank_line:
print('')
print('----------------------------------------------------------')
================================================
FILE: samples/show_workbook_info/geocoding.twbx
================================================
[File too large to display: 65.1 MB]
================================================
FILE: samples/show_workbook_info/show_workbook_info.py
================================================
############################################################
# Step 1) Use Datasource object from the Document API
############################################################
from tableaudocumentapi import Workbook
from lxml import etree as ET
############################################################
# Step 2) Open the .tds we want to explore
############################################################
sourceTWBX = Workbook('geocoding.twbx')
############################################################
# Step 3) List out info from the TWBX
############################################################
print('----------------------------------------------------------')
print('-- Info for our .twbx:')
print('-- name:\t{0}'.format(sourceTWBX.filename))
print('-- CONTENTS')
print('-- dashboards:\t{0}'.format(len(sourceTWBX.dashboards)))
for dash in sourceTWBX.dashboards:
print("-- {}".format(dash))
print('-- datasources:\t{0}'.format(len(sourceTWBX.datasources)))
for data in sourceTWBX.datasources:
print("-- {}".format(data.name))
print('-- worksheets:\t{0}'.format(len(sourceTWBX.worksheets)))
for data in sourceTWBX.worksheets:
print("-- {}".format(data))
print('-- shapes:\t{0}'.format(len(sourceTWBX.shapes)))
for shape in sourceTWBX.shapes:
print("-- {}".format(shape))
print('----------------------------------------------------------')
worksheets = sourceTWBX.worksheets
for worksheet in worksheets:
print("worksheet: {}".format(worksheet))
for datasource in sourceTWBX.datasources:
print("-- datasource: {}".format(datasource.name))
for count, field in enumerate(datasource.fields.values()):
if worksheet in field.worksheets:
print(field)
================================================
FILE: samples/show_workbook_info/world.tds
================================================
Birth Rate5[Birth Rate][Extract]Birth Rate0English$realSum48true0.00700000000000000010.052999999999999999true"array"true83"asc"1"double"Business Tax Rate5[Business Tax Rate][Extract]Business Tax Rate1English$realSum448true0.0820000000000000033.391true"array"true82"double"CO2 Emissions3[CO2 Emissions][Extract]CO2 Emissions2English$integerSum1744true782868924"sint32"Country129[Country][Extract]Country3English$stringCount20811073741823false"Afghanistan""Zimbabwe""en_US_CI"true"heap"true42949672922"asc"2"str"Days to Start Business2[Days to Start Business][Extract]Days to Start Business4English$integerSum127true1694true"array"true21"sint16"Ease of Business2[Ease of Business][Extract]Ease of Business5English$integerSum186true1189true"array"true21"sint16"Energy Usage3[Energy Usage][Extract]Energy Usage6English$integerSum1722true827277284"sint32"GDP20[GDP][Extract]GDP7English$integerSum2495true6310127221474836478"sint64"Health Exp % GDP5[Health Exp % GDP][Extract]Health Exp % GDP8English$realSum146true0.00800000000000000020.22500000000000001true"array"true81"double"Health Exp/Capita2[Health Exp/Capita][Extract]Health Exp/Capita9English$integerSum1070true299082"sint16"Hours to do Tax2[Hours to do Tax][Extract]Hours to do Tax10English$integerSum281true1226002"sint16"Infant Mortality Rate5[Infant Mortality Rate][Extract]Infant Mortality Rate11English$realSum130true0.0020.14099999999999999true"array"true81"double"Internet Usage5[Internet Usage][Extract]Internet Usage12English$realSum709true0.00.96199999999999997true"array"true82"double"Lending Interest5[Lending Interest][Extract]Lending Interest13English$realSum352true0.00500000000000000014.9649999999999999true"array"true82"double"Life Expectancy Female16[Life Expectancy Female][Extract]Life Expectancy Female14English$integerSum50true39871"sint8"Life Expectancy Male16[Life Expectancy Male][Extract]Life Expectancy Male15English$integerSum48true37881"sint8"Mobile Phone Usage5[Mobile Phone Usage][Extract]Mobile Phone Usage16English$realSum1179true0.02.8980000000000001true"array"true82"double"Number of Records16[Number of Records][Extract]Number of Records17integerSum1false11"asc"1"sint8"Population 0-145[Population 0-14][Extract]Population 0-1418English$realSum377true0.117999999999999990.5true"array"true82"double"Population 15-645[Population 15-64][Extract]Population 15-6419English$realSum299true0.473999999999999980.85799999999999998true"array"true82"double"Population 65+5[Population 65+][Extract]Population 65+20English$realSum209true0.00300000000000000010.24399999999999999true"array"true81"double"Population Total3[Population Total][Extract]Population Total21English$integerSum2699false1887613506950004"sint32"Population Urban5[Population Urban][Extract]Population Urban22English$realSum823true0.0820000000000000031.0true"array"true82"double"Region129[Region][Extract]Region23English$stringCount611073741823false"Africa""The Americas""en_US_CI"true"heap"true42949672921"asc"1"str"Tourism Inbound20[Tourism Inbound][Extract]Tourism Inbound24English$integerSum1651true7000002147483647true"array"true82"sint64"Tourism Outbound20[Tourism Outbound][Extract]Tourism Outbound25English$integerSum1458true2000002147483647true"array"true82"sint64"Year133[Year][Extract]Year26English$dateYear13false#2000-12-01##2012-12-01#true"array"true"asc"40"asc"1"date"% of population% of Commercial profitKilotonnes of oil equivalentTime required to start a business1=EaseKilotonnesGross domestic product Healthcare expenditure as % of GDPHealthcare expenditure per capitaTime to prepare and pay taxes for business% of PopulationPer CapitaA bank rate that meets private sectors' needs.Years a newborn would live if prevailing patterns are the sameYears a newborn would live if prevailing patterns are the samePer Capita% of population% of population% of populationTotal number of people in a country% of populationIncome from inbound tourismExpenditure for outbound tourism
================================================
FILE: setup.cfg
================================================
[wheel]
universal = 1
[pycodestyle]
select =
max_line_length = 120
[pep8]
max_line_length = 120
================================================
FILE: setup.py
================================================
from setuptools import setup
setup(
name='tableaudocumentapi',
version='0.11',
author='Tableau',
author_email='github@tableau.com',
url='https://github.com/tableau/document-api-python',
packages=['tableaudocumentapi'],
license='MIT',
description='A Python module for working with Tableau files.',
long_description="file: README.md",
long_description_content_type="text/markdown",
test_suite='test',
install_requires=['lxml']
)
================================================
FILE: tableaudocumentapi/__init__.py
================================================
from .field import Field
from .connection import Connection
from .datasource import Datasource, ConnectionParser
from .workbook import Workbook
__version__ = '0.0.1'
__VERSION__ = __version__
================================================
FILE: tableaudocumentapi/connection.py
================================================
from lxml import etree as ET
from tableaudocumentapi.dbclass import is_valid_dbclass
class Connection(object):
"""A class representing connections inside Data Sources."""
def __init__(self, connxml):
"""Connection is usually instantiated by passing in connection elements
in a Data Source. If creating a connection from scratch you can call
`from_attributes` passing in the connection attributes.
"""
self._connectionXML = connxml
self._dbname = connxml.get('dbname')
self._server = connxml.get('server')
self._username = connxml.get('username')
self._authentication = connxml.get('authentication')
self._class = connxml.get('class')
self._schema = connxml.get('schema')
self._service = connxml.get('service')
self._port = connxml.get('port', None)
self._query_band = connxml.get('query-band-spec', None)
self._initial_sql = connxml.get('one-time-sql', None)
def __repr__(self):
return "''".format(self._server, self._dbname, hex(id(self)))
@classmethod
def from_attributes(cls, server, dbname, username, dbclass, port=None, query_band=None,
initial_sql=None, authentication='', schema='', service=''):
"""Creates a new connection that can be added into a Data Source.
defaults to `''` which will be treated as 'prompt' by Tableau."""
root = ET.Element('connection', authentication=authentication)
xml = cls(root)
xml.server = server
xml.dbname = dbname
xml.username = username
xml.schema = schema
xml.service = service
xml.dbclass = dbclass
xml.port = port
xml.query_band = query_band
xml.initial_sql = initial_sql
return xml
@property
def dbname(self):
"""Database name for the connection. Not the table name."""
return self._dbname
@dbname.setter
def dbname(self, value):
"""
Set the connection's database name property.
Args:
value: New name of the database. String.
Returns:
Nothing.
"""
self._dbname = value
self._connectionXML.set('dbname', value)
@property
def server(self):
"""Hostname or IP address of the database server. May also be a URL in some connection types."""
return self._server
@server.setter
def server(self, value):
"""
Set the connection's server property.
Args:
value: New server. String.
Returns:
Nothing.
"""
self._server = value
self._connectionXML.set('server', value)
@property
def username(self):
"""Username used to authenticate to the database."""
return self._username
@username.setter
def username(self, value):
"""
Set the connection's username property.
Args:
value: New username value. String.
Returns:
Nothing.
"""
self._username = value
self._connectionXML.set('username', value)
@property
def authentication(self):
return self._authentication
@property
def dbclass(self):
"""The type of connection (e.g. 'MySQL', 'Postgresql'). A complete list
can be found in dbclass.py"""
return self._class
@dbclass.setter
def dbclass(self, value):
"""Set the connection's dbclass property.
Args:
value: New dbclass value. String.
Returns:
Nothing.
"""
if not is_valid_dbclass(value):
raise AttributeError("'{}' is not a valid database type".format(value))
self._class = value
self._connectionXML.set('class', value)
@property
def port(self):
"""Port used to connect to the database."""
return self._port
@port.setter
def port(self, value):
"""Set the connection's port property.
Args:
value: New port value. String.
Returns:
Nothing.
"""
self._port = value
# If port is None we remove the element and don't write it to XML
if value is None:
try:
del self._connectionXML.attrib['port']
except KeyError:
pass
else:
self._connectionXML.set('port', value)
@property
def query_band(self):
"""Query band passed on connection to database."""
return self._query_band
@query_band.setter
def query_band(self, value):
"""Set the connection's query_band property.
Args:
value: New query_band value. String.
Returns:
Nothing.
"""
self._query_band = value
# If query band is None we remove the element and don't write it to XML
if value is None:
try:
del self._connectionXML.attrib['query-band-spec']
except KeyError:
pass
else:
self._connectionXML.set('query-band-spec', value)
@property
def initial_sql(self):
"""Initial SQL to be run."""
return self._initial_sql
@initial_sql.setter
def initial_sql(self, value):
"""Set the connection's initial_sql property.
Args:
value: New initial_sql value. String.
Returns:
Nothing.
"""
self._initial_sql = value
# If initial_sql is None we remove the element and don't write it to XML
if value is None:
try:
del self._connectionXML.attrib['one-time-sql']
except KeyError:
pass
else:
self._connectionXML.set('one-time-sql', value)
@property
def schema(self):
"""Database schema for the connection. Not the table name."""
return self._schema
@schema.setter
def schema(self, value):
"""
Set the connection's schema property.
Args:
value: New name of the database schema. String.
Returns:
Nothing.
"""
self._schema = value
self._connectionXML.set('schema', value)
@property
def service(self):
"""Database service for the connection. Not the table name."""
return self._service
@service.setter
def service(self, value):
"""
Set the connection's service property.
Args:
value: New name of the database service. String.
Returns:
Nothing.
"""
self._service = value
self._connectionXML.set('service', value)
================================================
FILE: tableaudocumentapi/datasource.py
================================================
import collections
import itertools
from lxml import etree as ET
import xml.sax.saxutils as sax
from uuid import uuid4
from tableaudocumentapi import Connection, xfile
from tableaudocumentapi import Field
from tableaudocumentapi.multilookup_dict import MultiLookupDict
from tableaudocumentapi.xfile import xml_open
_ColumnObjectReturnTuple = collections.namedtuple('_ColumnObjectReturnTupleType', ['id', 'object'])
def _get_metadata_xml_for_field(root_xml, field_name):
if "'" in field_name:
field_name = sax.escape(field_name, {"'": "'"})
xpath = u".//metadata-record[@class='column'][local-name='{}']".format(field_name)
return root_xml.find(xpath)
def _is_used_by_worksheet(names, field):
return any(y for y in names if y in field.worksheets)
class FieldDictionary(MultiLookupDict):
def used_by_sheet(self, name):
# If we pass in a string, no need to get complicated, just check to see if name is in
# the field's list of worksheets
if isinstance(name, str):
return [x for x in self.values() if name in x.worksheets]
# if we pass in a list, we need to check to see if any of the names in the list are in
# the field's list of worksheets
return [x for x in self.values() if _is_used_by_worksheet(name, x)]
def _column_object_from_column_xml(root_xml, column_xml):
field_object = Field.from_column_xml(column_xml)
local_name = field_object.id
metadata_record = _get_metadata_xml_for_field(root_xml, local_name)
if metadata_record is not None:
field_object.apply_metadata(metadata_record)
return _ColumnObjectReturnTuple(field_object.id, field_object)
def _column_object_from_metadata_xml(metadata_xml):
field_object = Field.from_metadata_xml(metadata_xml)
return _ColumnObjectReturnTuple(field_object.id, field_object)
def base36encode(number):
"""Converts an integer into a base36 string."""
ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"
base36 = ''
sign = ''
if number < 0:
sign = '-'
number = -number
if 0 <= number < len(ALPHABET):
return sign + ALPHABET[number]
while number != 0:
number, i = divmod(number, len(ALPHABET))
base36 = ALPHABET[i] + base36
return sign + base36
def _make_unique_name(dbclass):
rand_part = base36encode(uuid4().int)
name = dbclass + '.' + rand_part
return name
class ConnectionParser(object):
"""Parser for detecting and extracting connections from differing Tableau file formats."""
def __init__(self, datasource_xml, version):
self._dsxml = datasource_xml
self._dsversion = version
def _extract_federated_connections(self):
connections = list(map(Connection, self._dsxml.findall('.//named-connections/named-connection/*')))
# 'sqlproxy' connections (Tableau Server Connections) are not embedded into named-connection elements
# extract them manually for now
connections.extend(map(Connection, self._dsxml.findall("./connection[@class='sqlproxy']")))
return connections
def _extract_legacy_connection(self):
return list(map(Connection, self._dsxml.findall('connection')))
def get_connections(self):
"""Find and return all connections based on file format version."""
if float(self._dsversion) < 10:
connections = self._extract_legacy_connection()
else:
connections = self._extract_federated_connections()
return connections
class Datasource(object):
"""A class representing Tableau Data Sources, embedded in workbook files or
in TDS files.
"""
def __init__(self, dsxml, filename=None):
"""
Constructor. Default is to create datasource from xml.
"""
self._filename = filename
self._datasourceXML = dsxml
self._datasourceTree = ET.ElementTree(self._datasourceXML)
self._name = self._datasourceXML.get('name') or self._datasourceXML.get(
'formatted-name') # TDS files don't have a name attribute
self._version = self._datasourceXML.get('version')
self._caption = self._datasourceXML.get('caption', '')
self._connection_parser = ConnectionParser(
self._datasourceXML, version=self._version)
self._connections = self._connection_parser.get_connections()
self._fields = None
@classmethod
def from_file(cls, filename):
"""Initialize datasource from file (.tds ot .tdsx)"""
dsxml = xml_open(filename, 'datasource').getroot()
return cls(dsxml, filename)
@classmethod
def from_connections(cls, caption, connections):
"""Create a new Data Source give a list of Connections."""
root = ET.Element('datasource', caption=caption, version='10.0', inline='true')
outer_connection = ET.SubElement(root, 'connection')
outer_connection.set('class', 'federated')
named_conns = ET.SubElement(outer_connection, 'named-connections')
for conn in connections:
nc = ET.SubElement(named_conns,
'named-connection',
name=_make_unique_name(conn.dbclass),
caption=conn.server)
nc.append(conn._connectionXML)
return cls(root)
def save(self):
"""
Call finalization code and save file.
Args:
None.
Returns:
Nothing.
"""
# save the file
xfile._save_file(self._filename, self._datasourceTree)
def save_as(self, new_filename):
"""
Save our file with the name provided.
Args:
new_filename: New name for the workbook file. String.
Returns:
Nothing.
"""
xfile._save_file(self._filename, self._datasourceTree, new_filename)
@property
def name(self):
""" Name of the datasource. """
return self._name
@property
def version(self):
""" Version of the datasource. """
return self._version
@property
def caption(self):
""" User defined name for the datasourse. """
return self._caption
@caption.setter
def caption(self, value):
self._datasourceXML.set('caption', value)
self._caption = value
@caption.deleter
def caption(self):
del self._datasourceXML.attrib['caption']
self._caption = ''
@property
def connections(self):
""" List of connections are used in workbook. """
return self._connections
def clear_repository_location(self):
tag = self._datasourceXML.find('./repository-location')
if tag is not None:
self._datasourceXML.remove(tag)
@property
def fields(self):
""" Key-value result of field's names and its attributes. Dict. """
if not self._fields:
self._refresh_fields()
return self._fields
def _refresh_fields(self):
self._fields = self._get_all_fields()
def _get_all_fields(self):
# Some columns are represented by `column` tags and others as `metadata-record` tags
# Find them all and chain them into one dictionary
column_field_objects = self._get_column_objects()
existing_column_fields = [x.id for x in column_field_objects]
metadata_only_field_objects = (x for x in self._get_metadata_objects() if x.id not in existing_column_fields)
field_objects = itertools.chain(column_field_objects, metadata_only_field_objects)
return FieldDictionary({k: v for k, v in field_objects})
def _get_metadata_objects(self):
return (_column_object_from_metadata_xml(x)
for x in self._datasourceTree.findall(".//metadata-record[@class='column']"))
def _get_column_objects(self):
return [_column_object_from_column_xml(self._datasourceTree, xml)
for xml in self._datasourceTree.findall('.//column')]
def _get_custom_sql(self):
return [qry for qry in self._datasourceXML.iter('relation')]
def add_field(self, name, datatype, role, field_type, caption, hidden):
""" Adds a base field object with the given values.
Args:
name: Name of the new Field. String.
datatype: Datatype of the new field. String.
role: Role of the new field. String.
field_type: Type of the new field. String.
caption: Caption of the new field. String.
Returns:
The new field that was created. Field.
"""
# TODO: A better approach would be to create an empty column and then
# use the input validation from its "Field"-object-representation to set values.
# However, creating an empty column causes errors :(
# If no caption is specified, create one with the same format Tableau does
if not caption:
caption = name.replace('[', '').replace(']', '').title()
# Create the elements
column = Field.create_field_xml(caption, datatype, hidden, role, field_type, name)
self._datasourceTree.getroot().append(column)
# Refresh fields to reflect changes and return the Field object
self._refresh_fields()
return self.fields[name]
def remove_field(self, field):
""" Remove a given field
Args:
field: The field to remove. ET.Element
Returns:
None
"""
if not field or not isinstance(field, Field):
raise ValueError("Need to supply a field to remove element")
self._datasourceTree.getroot().remove(field.xml)
self._refresh_fields()
###########
# Calculations
###########
@property
def calculations(self):
""" Returns all calculated fields.
"""
return {k: v for k, v in self.fields.items() if v.calculation is not None}
def add_calculation(self, caption, formula, datatype, role, type, hidden):
""" Adds a calculated field with the given values.
Args:
caption: Caption of the new calculation. String.
formula: Formula of the new calculation. String.
datatype: Datatype of the new calculation (string, integer, etc). String.
role: Role of the new calculation (Dimension or Measure). String.
type: Type of the new calculation (quantitative, ordinal, nominal). String.
hidden: Whether the new calculation is hidden. Boolean
Returns:
The new calculated field that was created. Field.
"""
# Dynamically create the name of the field
name = '[Calculation_{}]'.format(str(uuid4().int)[:18])
field = self.add_field(name, datatype, role, type, caption, hidden)
field.calculation = formula
return field
================================================
FILE: tableaudocumentapi/dbclass.py
================================================
KNOWN_DB_CLASSES = ('msaccess',
'msolap',
'bigquery',
'asterncluster',
'bigsql',
'composite',
'aurora',
'awshadoophive',
'dataengine',
'DataStax',
'db2',
'essbase',
'exasolution',
'excel',
'excel-direct',
'excel-reader',
'firebird',
'powerpivot',
'genericodbc',
'google-analytics',
'googlecloudsql',
'google-sheets',
'greenplum',
'saphana',
'hadoophive',
'hortonworkshadoophive',
'maprhadoophive',
'marklogic',
'memsql',
'mysql',
'netezza',
'oracle',
'paraccel',
'postgres',
'progressopenedge',
'redshift',
'snowflake',
'spark',
'splunk',
'kognitio',
'sqlserver',
'salesforce',
'sapbw',
'sybasease',
'sybaseiq',
'tbio',
'teradata',
'vectorwise',
'vertica',
'denormalized-cube',
'csv',
'textscan',
'webdata',
'webdata-direct',
'cubeextract')
def is_valid_dbclass(dbclass):
return dbclass in KNOWN_DB_CLASSES
================================================
FILE: tableaudocumentapi/field.py
================================================
import functools
from lxml import etree as ET
from xml.dom import minidom
from tableaudocumentapi.property_decorators import argument_is_one_of
_ATTRIBUTES = [
'id', # Name of the field as specified in the file, usually surrounded by [ ]
'caption', # Name of the field as displayed in Tableau unless an aliases is defined
'datatype', # Type of the field within Tableau (string, integer, etc)
'role', # Dimension or Measure
'type', # three possible values: quantitative, ordinal, or nominal
'alias', # Name of the field as displayed in Tableau if the default name isn't wanted
'calculation', # If this field is a calculated field, this will be the formula
'description', # If this field has a description, this will be the description (including formatting tags)
'hidden', # If this field has been hidden
]
_METADATA_ATTRIBUTES = [
'aggregation', # The type of aggregation on the field (e.g Sum, Avg)
]
_METADATA_TO_FIELD_MAP = [
('local-name', 'id'),
('local-type', 'datatype'),
('remote-alias', 'alias')
]
def _find_metadata_record(record, attrib):
element = record.find('.//{}'.format(attrib))
if element is None:
return None
return element.text
class Field(object):
""" Represents a field in a datasource """
def __init__(self, column_xml=None, metadata_xml=None):
# Initialize all the possible attributes
for attrib in _ATTRIBUTES:
setattr(self, '_{}'.format(attrib), None)
for attrib in _METADATA_ATTRIBUTES:
setattr(self, '_{}'.format(attrib), None)
self._worksheets = set()
if column_xml is not None:
self._initialize_from_column_xml(column_xml)
self._xml = column_xml
# This isn't currently called because of the way we get the data from the xml,
# but during the refactor, we might need it. This is commented out as a reminder
# if metadata_xml is not None:
# self.apply_metadata(metadata_xml)
elif metadata_xml is not None:
self._xml = metadata_xml
self._initialize_from_metadata_xml(metadata_xml)
else:
raise AttributeError('column_xml or metadata_xml needed to initialize field')
def _initialize_from_column_xml(self, xmldata):
for attrib in _ATTRIBUTES:
self._apply_attribute(xmldata, attrib, lambda x: xmldata.attrib.get(x, None))
def _initialize_from_metadata_xml(self, xmldata):
for metadata_name, field_name in _METADATA_TO_FIELD_MAP:
self._apply_attribute(xmldata, field_name,
lambda x: getattr(xmldata.find('.//{}'.format(metadata_name)), 'text', None),
read_name=metadata_name)
self.apply_metadata(xmldata)
@classmethod
def create_field_xml(cls, caption, datatype, hidden, role, field_type, name):
column = ET.Element('column')
column.set('caption', caption)
column.set('datatype', datatype)
column.set('hidden', hidden)
column.set('role', role)
column.set('type', field_type)
column.set('name', name)
return column
########################################
# Special Case methods for construction fields from various sources
# not intended for client use
########################################
def apply_metadata(self, metadata_record):
for attrib in _METADATA_ATTRIBUTES:
self._apply_attribute(metadata_record, attrib, functools.partial(_find_metadata_record, metadata_record))
def add_used_in(self, name):
self._worksheets.add(name)
@classmethod
def from_column_xml(cls, xmldata):
return cls(column_xml=xmldata)
@classmethod
def from_metadata_xml(cls, xmldata):
return cls(metadata_xml=xmldata)
def _apply_attribute(self, xmldata, attrib, default_func, read_name=None):
if read_name is None:
read_name = attrib
if hasattr(self, '_read_{}'.format(read_name)):
value = getattr(self, '_read_{}'.format(read_name))(xmldata)
else:
value = default_func(attrib)
setattr(self, '_{}'.format(attrib), value)
@property
def name(self):
""" Provides a nice name for the field which is derived from the alias, caption, or the id.
The name resolves as either the alias if it's defined, or the caption if alias is not defined,
and finally the id which is the underlying name if neither of the fields exist. """
alias = getattr(self, 'alias', None)
if alias:
return alias
caption = getattr(self, 'caption', None)
if caption:
return caption
return self.id
@property
def id(self):
""" Name of the field as specified in the file, usually surrounded by [ ] """
return self._id
@property
def xml(self):
""" XML representation of the field. """
return self._xml
def pretty_xml(self):
"""Return a pretty-printed XML string for the Element.
"""
rough_string = ET.tostring(self._xml, 'utf-8')
prepared_string = minidom.parseString(rough_string)
print_string = prepared_string.toprettyxml(indent=" ", newl="")
return print_string.lstrip('')
def __str__(self):
""" String representation of the field (only includes usable attributes) """
# TODO: ideally this should just loop through the ATTRIBUTES so it doesn't need touching for new ones
output = "------ FIELD {} ({}/{}/{}): {}(type), {}(datatype), {}(role), {}(aggregation)".format(
self.name, self.caption, self.alias, self.id, self.type, self.datatype, self.role, self.default_aggregation)
return output
def detailed_str(self):
if self.calculation:
calc = "\ncalc: `{}`".format(self.calculation)
else:
calc = ""
########################################
# Attribute getters and setters
########################################
@property
def caption(self):
""" Name of the field as displayed in Tableau unless an aliases is defined """
return self._caption
@caption.setter
def caption(self, caption):
""" Set the caption of a field
Args:
caption: New caption. String.
Returns:
Nothing.
"""
self._caption = caption
self._xml.set('caption', caption)
@property
def alias(self):
""" Name of the field as displayed in Tableau if the default name isn't wanted """
return self._alias
@alias.setter
def alias(self, alias):
""" Set the alias of a field
Args:
alias: New alias. String.
Returns:
Nothing.
"""
self._alias = alias
self._xml.set('alias', alias)
@property
def datatype(self):
""" Type of the field within Tableau (string, integer, etc) """
return self._datatype
@datatype.setter
@argument_is_one_of('string', 'integer', 'date', 'boolean')
def datatype(self, datatype):
""" Set the datatype of a field
Args:
datatype: New datatype. String.
Returns:
Nothing.
"""
self._datatype = datatype
self._xml.set('datatype', datatype)
@property
def hidden(self):
""" If the column is Hidden ('true', 'false') """
return self._hidden
@hidden.setter
@argument_is_one_of('true', 'false')
def hidden(self, hidden):
""" Set the hidden property of a field
Args:
hidden: New hidden. String.
Returns:
Nothing.
"""
self._hidden = hidden
self._xml.set('hidden', hidden)
@property
def role(self):
""" Dimension or Measure """
return self._role
@role.setter
@argument_is_one_of('dimension', 'measure')
def role(self, role):
""" Set the role of a field
Args:
role: New role. String.
Returns:
Nothing.
"""
self._role = role
self._xml.set('role', role)
@property
def type(self):
""" Type of field (quantitative, ordinal, nominal) """
return self._type
@type.setter
@argument_is_one_of('quantitative', 'ordinal', 'nominal')
def type(self, field_type):
""" Set the type of a field
Args:
field_type: New type. String.
Returns:
Nothing.
"""
self._type = field_type
self._xml.set('type', field_type)
########################################
# Aliases getter and setter
# Those are NOT the 'alias' field of the column,
# but instead the key-value aliases in its child elements
########################################
def add_alias(self, key, value):
""" Add an alias for a given display value.
Args:
key: The data value to map. Example: "1". String.
value: The display value for the key. Example: "True". String.
Returns:
Nothing.
"""
# determine whether there already is an aliases-tag
aliases = self._xml.find('aliases')
# and create it if there isn't
if not aliases: # ignore the FutureWarning, does not apply to our usage
aliases = ET.Element('aliases')
self._xml.append(aliases)
# find out if an alias with this key already exists and use it
existing_alias = [tag for tag in aliases.findall('alias') if tag.get('key') == key]
# if not, create a new ET.Element
alias = existing_alias[0] if existing_alias else ET.Element('alias')
alias.set('key', key)
alias.set('value', value)
if not existing_alias:
aliases.append(alias)
@property
def aliases(self):
""" Returns all aliases that are registered under this field.
Returns:
Key-value mappings of all registered aliases. Dict.
"""
aliases_tag = self._xml.find('aliases') or [] # ignore the FutureWarning, does not apply to our usage
return {a.get('key', 'None'): a.get('value', 'None') for a in list(aliases_tag)}
########################################
# Attribute getters
########################################
@property
def is_quantitative(self):
""" A dependent value, usually a measure of something
e.g. Profit, Gross Sales """
return self.type == 'quantitative'
@property
def is_ordinal(self):
""" Is this field a categorical field that has a specific order
e.g. How do you feel? 1 - awful, 2 - ok, 3 - fantastic """
return self.type == 'ordinal'
@property
def is_nominal(self):
""" Is this field a categorical field that does not have a specific order
e.g. What color is your hair? """
return self.type == 'nominal'
@property
def calculation(self):
""" If this field is a calculated field, this will be the formula """
return self._calculation
@calculation.setter
def calculation(self, new_calculation):
""" Set the calculation of a calculated field.
Args:
new_calculation: The new calculation/formula of the field. String.
"""
if self.calculation is None:
calculation = ET.Element('calculation')
calculation.set('class', 'tableau')
calculation.set('formula', new_calculation)
# Append the elements to the respective structure
self._xml.append(calculation)
else:
self._xml.find('calculation').set('formula', new_calculation)
self._calculation = new_calculation
@property
def default_aggregation(self):
""" The default type of aggregation on the field (e.g Sum, Avg)"""
return self._aggregation
@property
def description(self):
""" The contents of the tag on a field """
return self._description
@property
def worksheets(self):
""" Worksheets which uses field. """
return list(self._worksheets)
######################################
# Special Case handling methods for reading the values from the XML
######################################
@staticmethod
def _read_id(xmldata):
# ID is actually the name of the field, but to provide a nice name, we call this ID
return xmldata.attrib.get('name', None)
@staticmethod
def _read_calculation(xmldata):
# The formula for a calculation is stored in a child element, so we need to pull it out separately.
calc = xmldata.find('.//calculation')
if calc is None:
return None
return calc.attrib.get('formula', None)
@staticmethod
def _read_description(xmldata):
description = xmldata.find('.//desc')
if description is None:
return None
description_string = ET.tostring(description, encoding='utf-8')
# Format expects a unicode string so in Python 2 we have to do the explicit conversion
if isinstance(description_string, bytes):
description_string = description_string.decode('utf-8')
return description_string
================================================
FILE: tableaudocumentapi/multilookup_dict.py
================================================
import weakref
_no_default_value = object()
def _resolve_value(key, value):
retval = None
try:
if hasattr(value, 'get'):
retval = value.get(key, None)
if retval is None:
retval = getattr(value, key, None)
except AttributeError:
# We should never hit this.
retval = None
return retval
def _build_index(key, d):
return {_resolve_value(key, v): k
for k, v in d.items()
if _resolve_value(key, v) is not None}
# TODO: Improve this to be more generic
class MultiLookupDict(dict):
def __init__(self, args=None):
if args is None:
args = {}
super(MultiLookupDict, self).__init__(args)
self._indexes = {
'alias': weakref.WeakValueDictionary(),
'caption': weakref.WeakValueDictionary()
}
self._populate_indexes()
def _populate_indexes(self):
self._indexes['alias'] = _build_index('alias', self)
self._indexes['caption'] = _build_index('caption', self)
def _get_real_key(self, key):
if key in self._indexes['alias']:
return self._indexes['alias'][key]
if key in self._indexes['caption']:
return self._indexes['caption'][key]
return key
def __setitem__(self, key, value):
real_key = self._get_real_key(key)
dict.__setitem__(self, real_key, value)
def get(self, key, default_value=_no_default_value):
try:
return self[key]
except KeyError:
if default_value is not _no_default_value:
return default_value
raise
def __getitem__(self, key):
real_key = self._get_real_key(key)
return dict.__getitem__(self, real_key)
================================================
FILE: tableaudocumentapi/property_decorators.py
================================================
from functools import wraps
def argument_is_one_of(*allowed_values):
def property_type_decorator(func):
@wraps(func)
def wrapper(self, value):
if value not in allowed_values:
error = "Invalid argument: {0}. {1} must be one of {2}."
msg = error.format(value, func.__name__, allowed_values)
raise ValueError(error)
return func(self, value)
return wrapper
return property_type_decorator
================================================
FILE: tableaudocumentapi/workbook.py
================================================
import weakref
from tableaudocumentapi import Datasource, xfile
from tableaudocumentapi.xfile import xml_open, TableauInvalidFileException
class Workbook(object):
"""A class for writing Tableau workbook files."""
def __init__(self, filename):
"""Open the workbook at `filename`. This will handle packaged and unpacked
workbook files automatically. This will also parse Data Sources and Worksheets
for access.
"""
self._filename = filename
self._workbookTree = xml_open(self._filename, 'workbook')
if not self._workbookTree:
raise TableauInvalidFileException("Workbook file must have a workbook element at root")
self._workbookRoot = self._workbookTree.getroot()
self._dashboards = self._prepare_dashboards(self._workbookRoot)
self._datasources = self._prepare_datasources(
self._workbookRoot)
self._datasource_index = self._prepare_datasource_index(self._datasources)
self._worksheets = self._prepare_worksheets(
self._workbookRoot, self._datasource_index)
self._shapes = self._prepare_shapes(self._workbookRoot)
@property
def dashboards(self):
return self._dashboards
@property
def datasources(self):
return self._datasources
@property
def worksheets(self):
return self._worksheets
@property
def filename(self):
return self._filename
@property
def shapes(self):
return self._shapes
def save(self):
"""
Call finalization code and save file.
Args:
None.
Returns:
Nothing.
"""
# save the file
xfile._save_file(self._filename, self._workbookTree)
def save_as(self, new_filename):
"""
Save our file with the name provided.
Args:
new_filename: New name for the workbook file. String.
Returns:
Nothing.
"""
xfile._save_file(
self._filename, self._workbookTree, new_filename)
@staticmethod
def _prepare_datasource_index(datasources):
retval = weakref.WeakValueDictionary()
for datasource in datasources:
retval[datasource.name] = datasource
return retval
@staticmethod
def _prepare_datasources(xml_root):
datasources = []
# loop through our datasources and append
datasource_elements = xml_root.find('datasources')
if datasource_elements is None:
return []
for datasource in datasource_elements:
ds = Datasource(datasource)
datasources.append(ds)
return datasources
@staticmethod
def _prepare_dashboards(xml_root):
dashboards = []
dashboard_elements = xml_root.find('.//dashboards')
if dashboard_elements is None:
return []
for dash_element in dashboard_elements:
dash_name = dash_element.attrib['name']
dashboards.append(dash_name)
return dashboards
@staticmethod
def _prepare_worksheets(xml_root, ds_index):
worksheets = []
worksheets_element = xml_root.find('.//worksheets')
if worksheets_element is None:
return worksheets
for worksheet_element in worksheets_element:
worksheet_name = worksheet_element.attrib['name']
worksheets.append(worksheet_name) # TODO: A real worksheet object, for now, only name
dependencies = worksheet_element.findall('.//datasource-dependencies')
for dependency in dependencies:
datasource_name = dependency.attrib['datasource']
datasource = ds_index[datasource_name]
for column in dependency.findall('.//column'):
column_name = column.attrib['name']
if column_name in datasource.fields:
datasource.fields[column_name].add_used_in(worksheet_name)
return worksheets
@staticmethod
def _prepare_shapes(xml_root):
shapes = []
worksheets_element = xml_root.find('.//external/shapes')
if worksheets_element is None:
return shapes
for worksheet_element in worksheets_element:
shape_name = worksheet_element.attrib['name']
shapes.append(shape_name)
return shapes
================================================
FILE: tableaudocumentapi/xfile.py
================================================
import contextlib
import os
import shutil
import tempfile
import zipfile
from lxml import etree as ET
from distutils.version import LooseVersion as Version
MIN_SUPPORTED_VERSION = Version("9.0")
class TableauVersionNotSupportedException(Exception):
pass
class TableauInvalidFileException(Exception):
pass
def xml_open(filename, expected_root=None):
"""Opens the provided 'filename'. Handles detecting if the file is an archive,
detecting the document version, and validating the root tag."""
# Is the file a zip (.twbx or .tdsx)
if zipfile.is_zipfile(filename):
tree = get_xml_from_archive(filename)
else:
_register_all_namespaces()
tree = ET.parse(filename)
# Is the file a supported version
tree_root = tree.getroot()
file_version = Version(tree_root.attrib.get('version', '0.0'))
if file_version < MIN_SUPPORTED_VERSION:
raise TableauVersionNotSupportedException(file_version)
# Does the root tag match the object type (workbook or data source)
if expected_root and (expected_root != tree_root.tag):
if expected_root == 'workbook' and tree_root.tag == 'datasource':
return # A .twbx can contain .tds files if it contains custom geocoding.
raise TableauInvalidFileException(
"'{}'' is not a valid '{}' file".format(filename, expected_root))
return tree
@contextlib.contextmanager
def temporary_directory(*args, **kwargs):
d = tempfile.mkdtemp(*args, **kwargs)
try:
yield d
finally:
shutil.rmtree(d)
def _register_all_namespaces():
# TO DO: should look at the file to find namespaces, not hardcode this one
ET.register_namespace("user", "http://www.tableausoftware.com/xml/user")
def find_file_in_zip(zip_file):
'''Returns the twb/tds file from a Tableau packaged file format. Packaged
files can contain cache entries which are also valid XML, so only look for
files with a .tds or .twb extension.
'''
candidate_files = filter(lambda x: x.split('.')[-1] in ('twb', 'tds'),
zip_file.namelist())
for filename in candidate_files:
with zip_file.open(filename) as xml_candidate:
try:
ET.parse(xml_candidate)
return filename
except ET.ParseError:
# That's not an XML file by gosh
pass
def get_xml_from_archive(filename):
with zipfile.ZipFile(filename, allowZip64=True) as zf:
with zf.open(find_file_in_zip(zf)) as xml_file:
xml_tree = ET.parse(xml_file)
return xml_tree
def build_archive_file(archive_contents, zip_file):
"""Build a Tableau-compatible archive file."""
# This is tested against Desktop and Server, and reverse engineered by lots
# of trial and error. Do not change this logic.
for root_dir, _, files in os.walk(archive_contents):
relative_dir = os.path.relpath(root_dir, archive_contents)
for f in files:
temp_file_full_path = os.path.join(
archive_contents, relative_dir, f)
zipname = os.path.join(relative_dir, f)
zip_file.write(temp_file_full_path, arcname=zipname)
def save_into_archive(xml_tree, filename, new_filename=None):
# Saving an archive means extracting the contents into a temp folder,
# saving the changes over the twb/tds in that folder, and then
# packaging it back up into a zip with a very specific format
# e.g. no empty files for directories, which Windows and Mac do by default
if new_filename is None:
new_filename = filename
# Extract to temp directory
with temporary_directory() as temp_path:
with zipfile.ZipFile(filename, allowZip64=True) as zf:
xml_file = find_file_in_zip(zf)
zf.extractall(temp_path)
# Write the new version of the file to the temp directory
xml_tree.write(os.path.join(
temp_path, xml_file), encoding="utf-8", xml_declaration=True)
# Write the new archive with the contents of the temp folder
with zipfile.ZipFile(new_filename, "w", compression=zipfile.ZIP_DEFLATED, allowZip64=True) as new_archive:
build_archive_file(temp_path, new_archive)
def _save_file(container_file, xml_tree, new_filename=None):
_register_all_namespaces() # this shouldn't be necessary, should be done on open
if new_filename is None:
new_filename = container_file
if zipfile.is_zipfile(container_file):
save_into_archive(xml_tree, container_file, new_filename)
else:
xml_tree.write(new_filename, encoding="utf-8", xml_declaration=True)
================================================
FILE: test/__init__.py
================================================
================================================
FILE: test/assets/.gitignore
================================================
field_change_test_output.tds
================================================
FILE: test/assets/CONNECTION.xml
================================================
================================================
FILE: test/assets/TABLEAU_10_TDS.tds
================================================
================================================
FILE: test/assets/TABLEAU_10_TWB.twb
================================================
================================================
FILE: test/assets/TABLEAU_82_TWB.twb
================================================
================================================
FILE: test/assets/TABLEAU_93_TDS.tds
================================================
================================================
FILE: test/assets/TABLEAU_93_TWB.twb
================================================
================================================
FILE: test/assets/__init__.py
================================================
================================================
FILE: test/assets/datasource_test.tds
================================================
a130[a][xy]a1stringCount255true"SQL_WVARCHAR""SQL_C_WCHAR""true"Today's Date130[Today's Date][xy]a1stringCount255true"SQL_WVARCHAR""SQL_C_WCHAR""true"x3[x][xy]x2integerSum10true"SQL_INTEGER""SQL_C_SLONG"y3[y][xy]y3integerSum10true"SQL_INTEGER""SQL_C_SLONG"z1[z][z]ztrue"SQL_INTEGER""SQL_C_SLONG"A thing
Something will go here too, in a muted gray
================================================
FILE: test/assets/datasource_test.twb
================================================
a130[a][xy]a1stringCount255true"SQL_WVARCHAR""SQL_C_WCHAR""true"x3[x][xy]x2integerSum10true"SQL_INTEGER""SQL_C_SLONG"y3[y][xy]y3integerSum10true"SQL_INTEGER""SQL_C_SLONG"
================================================
FILE: test/assets/field_change_test.tds
================================================
name130[name][my_data]name1stringCount8190truetrue"SQL_WLONGVARCHAR""SQL_C_WCHAR"typ130[typ][my_data]typ2stringCount8190truetrue"SQL_WLONGVARCHAR""SQL_C_WCHAR"amount3[amount][my_data]amount3integerSum10true"SQL_INTEGER""SQL_C_SLONG"price5[price][my_data]price4realSum17true"SQL_FLOAT""SQL_C_DOUBLE"
================================================
FILE: test/assets/filtering.twb
================================================
<_.fcp.GroupActionAddRemove.true...GroupActionAddRemove />
<_.fcp.MarkAnimation.true...MarkAnimation />
<_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy />
<_.fcp.ObjectModelTableType.true...ObjectModelTableType />
<_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel />
<_.fcp.SetMembershipControl.true...SetMembershipControl />
<_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m' name='TestData' table='[dbo].[TestData]' type='table' />
<_.fcp.ObjectModelEncapsulateLegacy.true...relation connection='sqlserver.1nzmabo1alszdd1dqm0c11g0qr0m' name='TestData' table='[dbo].[TestData]' type='table' />
Account Account Name130[Account Account Name][TestData]Account Account Name1stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Account Number5[Account Number][TestData]Account Number2realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Account Number Burst Out Account130[Account Number Burst Out Account][TestData]Account Number Burst Out Account3stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Acct Name130[Acct Name][TestData]Acct Name4stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out130[Burst Out][TestData]Burst Out5stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Join130[Burst Out Join][TestData]Burst Out Join6stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out Set list5[Burst Out Set list][TestData]Burst Out Set list7realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Burst Out View5[Burst Out View][TestData]Burst Out View8realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count JE Number5[Count JE Number][TestData]Count JE Number9realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Entity ID130[Entity ID][TestData]Entity ID10stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Filter5[Filter][TestData]Filter11realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Fiscal Year130[Fiscal Year][TestData]Fiscal Year12stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag11[Flag][TestData]Flag13booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Flag__copy_11[Flag__copy_][TestData]Flag__copy_14booleanCountfalse"SQL_BIT""SQL_C_BIT"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line5[FS Line][TestData]FS Line15realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
FS Line Burst Out Account130[FS Line Burst Out Account][TestData]FS Line Burst Out Account16stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Group By5[Group By][TestData]Group By17realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Image130[Image][TestData]Image18stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line5[Note Line][TestData]Note Line19realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Note Line Burst Out Account130[Note Line Burst Out Account][TestData]Note Line Burst Out Account20stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Selection5[Selection][TestData]Selection21realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
show130[show][TestData]show22stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Show Cycle Based130[Show Cycle Based][TestData]Show Cycle Based23stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sub Class5[Sub Class][TestData]Sub Class24realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
SubClass Burst Out Account130[SubClass Burst Out Account][TestData]SubClass Burst Out Account25stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Type130[Type][TestData]Type26stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount130[Amount][TestData]Amount27stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Amount1130[Amount1][TestData]Amount128stringCount255truetrue"SQL_WVARCHAR""SQL_C_WCHAR""true"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Count of Amount Calculation5[Count of Amount Calculation][TestData]Count of Amount Calculation29realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records5[Number of Records][TestData]Number of Records30realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Number of Records15[Number of Records1][TestData]Number of Records131realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Burst Out5[Select Burst Out][TestData]Select Burst Out32realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Select Transaction Analysis view5[Select Transaction Analysis view][TestData]Select Transaction Analysis view33realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Cy5[Sum Cy][TestData]Sum Cy34realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py15[Sum Py1][TestData]Sum Py135realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py25[Sum Py2][TestData]Sum Py236realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py35[Sum Py3][TestData]Sum Py337realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Sum Py45[Sum Py4][TestData]Sum Py438realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Credits5[Total Credits][TestData]Total Credits39realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
Total Debits5[Total Debits][TestData]Total Debits40realSum15true"SQL_FLOAT""SQL_C_DOUBLE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[TestData_44D2C885FAEF453C846AC2CCD3577055]
<_.fcp.ObjectModelTableType.true...column caption='TestData' datatype='table' name='[__tableau_internal_object_id__].[TestData_44D2C885FAEF453C846AC2CCD3577055]' role='measure' type='quantitative' />
<_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
<_.fcp.GroupActionAddRemove.true...add-or-remove-marks value='assign' />
Selection
([federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Calculation_88946136969252864:nk] / [federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk])
Set Result
([federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk] / [federated.1df63xu0j2dvhd1e3sooz18pbrcc].[io:BurstoutSet:nk])
[federated.1df63xu0j2dvhd1e3sooz18pbrcc].[io:BurstoutSet:nk][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Acct Name:nk][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst-Out Set list:ok][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst Out Set list:nk][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Burst-Out Set list:ok][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Calculation_88946136969252864:nk][federated.1df63xu0j2dvhd1e3sooz18pbrcc].[none:Calculation_968836911996190720:nk]
iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAA7DAAAOwwHHb6hk
AAAgAElEQVR4nO3dd3gc933n8feU7Qtgsei9gyTYQLB3kRQpUaK6bVnFsmIpjnPJ2bEd5+65
5J4nd0/85EouZyWX09kpju04emxFnaqkCotIsFeAANF7X2B7nZn7gxAJkqBkiLBEaH+v/3Yw
s1zOzmfmN7O/7+8nGYZhIAhJSJIkSf68P4QgfJ5EAISkJgIgJDURACGpiQAISU0EQEhqIgBC
UhMBEJKaCICQ1EQAhKQmAiAkNREAIamJAAhJTQRASGoiAEJSEwEQkpoIgJDURACEpCYCICQ1
EQAhqYkACElNBEBIauqN/mAYBmLEFOGL7oYBiEajtLa2fpafRZhjYrEYJpMJSZI+74/yqUli
YCzh02pubqasrAyz2fx5f5RPRQyMJSQ9EQAhqd3wHuBGtIiXCwdf4sW3TzISs1NUdwdPfnUT
2RZlmrVj9F84wIf1CVY9fAcl9ln4xB9j9MMf87eDm/gvDy347f5DwmfGSITpOv0OL7z0Ph0+
icJVD/H0l9eQaYGxtmO8/Kt/48ywjWUPfYPH1pdhVq65Hwn38uKzz/B+J1Su28VDuzZS6Lxy
3p/ZFcBIMNj8Dq+8McSKx7/Hn3z3CepiFzg1lLjBBjoh7yDdbQMEb7TKtPp4669/xC/3dxDV
fvOtYiOtnO3xzuQfmhVH/vWH/MPr5wl+dDs1cZqfvXb+Y7fxdjVx9Eg9QxFg/Dg/29302/+g
c9D4SJD33/Wz7rFv8x//5JssHX+TV88HiI33c/zQh6irf4fvfut2fK+9yCFP5OqNjQhnfvX3
tFU8yve/8ygFgSYOHW4iOOWud2ZXAF0jPDSMT82lpCKPAoeZot+tufRvaXECE6OMecPosgVX
djbptms+TzzE6PAIvoiGyZZKRpYbh0lGjwUYHR7FH9OxWO2YlSF6e3sZzeqgo0AiJ78UlymK
d3yUcX8EQ7GRmZtLqhnikQCeMQ/BmMGYJ/xp9vFNU+KZuCwXON1eypoKJ4oewx/UP3YbPREn
Go2gGYAWwx+KfTYfdo5Jz83kiT9+HEUB9DiOZSU8r0tM+Hrw+Gu4Y+sicmX4+j3HefaEj9vu
nHLQhc+xp3cZX39sCdkmmZTgGB/0dDPkX0B56qUrxcwCIKukl88nV3qb1//1NQYWlVNeWU1p
po3AQANvvbSbk90TJDSJzJVf4Q8eXnRlWyNE77E9/Nt7x+gdD2Ny5LH6roe5sy6F9vde4Nfv
XcCvy+SWlpObGqW+uYnxkQBjjVlsf/o/s0w7zhuv7aVxwIemK5Rv/yZP3Obm4nsv8uq+BnxY
sEz0YnwOrR/VlkJ+SQmB1kZGC1aQ89Ef9AR+/zgRPYWsdCsQoK89TFZ51mf/IecoSQJFMdAi
Xno7WjnTlcP6uxXi/ihGeiGZk20YV8U8tHdH4creB78fqayYdEkCJNIzUpEHAoTDGqReOvRn
FgBJwV22nkeesnHgwEmO7TnNvgPz+OqT96Idf4N3zoWoXbMI6+hZXnnubXZ+qQbHR9sG23n9
+b305MyjdpGZ3oaz1O87yuLMdJ7b003to9/n/mVZJCIhDGUCZ9sEI+sf5evbqjBHBnnvV3s4
2iOzeOlilIEjvPGLt1k5fxnHT7Qx78Ef8OCqHAZf+BP+qO9md/mnIJnIzCvCPNhAb8847ozJ
5VqY3vbz9CXmcfvKfGCAD9/oZusfbmO6OyZhOgYx3zAXG0/RPGKhZusWql1WBn06yBKXW/yS
RCx6zVXU0EG+0sqXgISmoetXrs4zvgmWFCu51ev4UsUKfIOn+flfPMMrJ1Zz25iHWFo+Ga5U
LK4N/E5lHjmKTOCjDQPjDIbNZGS6cKbZmb9uBxklC0j1nWYovYoVFemosopqTwUmrv5/xKL4
fEFwlZCeloopbTtP1ZZgDw+SkBwUF+RjkcFk+vweaimOTEqyUzk71MO4VeNT7FphGlrYT+e5
ejqNctZsqiIvzYqMhoIFyTvMhA4ZMgT7e7Dn1V29scOJ0TdIwFhMOgZ+XwhVArvNdHmVmR0x
WoyhE2/wyrEu/JqM3QKRiIbF7iQtLxeXYaFy9R3cf+9drF+YffVZzpVNiTNGSK1kx333s2vH
eqrzU7Bk51MydJJ3Tg8R12ME/R4CYRWzJczoqJe4ngCzFXeGC4cpg6Wb7uKBe3dSV5GGzeYG
vHT3DxCJ+hkeC9zgg38GJBPu4kJsvjH6RiaY0T2/cEN+v0Zju41ldTXkp1knD1iZFGs2Nuk8
9RfGiHhb2L17lKqa1Ks3dlRRq9bzyqkRoqEhTp3rIKS5cDuvPCmaYRNIRjbpNPz8L/jlfx/B
UDOYd8e3+M6qbByBu9l84Sf86DtPEJItFC18iB/8WR6SrKCoOrK1gnuf3MH/+8mzfP2V/4Ep
rYTNDzzGl+9cyTefHuXHP/kzvvK3MUqX7+Qbv/c16rYsYv8//k+e2u3kq3/+E7Ztup2On/2c
P/+954kqdhZvfIrf/+ZS1tUW8U/P/AEvmStYmu1FLfocrwLWXJZUtvD6mQ5CkUyQJGRDJxEO
EQx5GW08Q3vMydbP7RPOPaGQj5d/8SN++uKzl8/WVV/9S/77l0pZtqyYn//ff88/j6Sy4uGn
+f0iO/j7eW//PjzZm/nSyjw2PXofP/4f3+fxv1Ko2vAgX39sCWlTjnrRFWIWNL3zDo4dOygC
wMvpl59nb6KOP/5SLf6BJt7fvZuzI2ZKlpdjHsrkjifWIfe00Do8QeHClWRHTvPcETuP3FH9
Of9PZuaL0BVCBED41L4IARBdIYSkJgIgJDURACGpiYfVMxAOfz5dLW5VmqYRiUTQtBl02LrF
iADMgHhecL25XjormkBCUhMBEJKaaAIJtzRDizJ48QjvfXCC/qBE9sIt3LdtES4TePsa2bfn
fVrGLczbuos7FudjurYgJjrMBy/8ihODULh4A1s21JJt+7RdIYRpTZx7nX/Z1zH5ysGCrTvZ
MC8HOTJG67mTNPtsLK1bRVmmBQyDRMRHV9MJTg0o1C5bTmWeEzDQYgH6Lp7lVEuYipXLmV+Y
nvRfkG8syL693WQvW8d8a5zO+jfZW1TGfcVBzh45wFj6UjZWeal/9Q3OlD7BCpdlytYxWt56
jlPKYjaug9bGMxw9lca2deV8VDWQ7Pt3Vvg8I1Ru/RprCwAkTDY7JnTO7X8TT+YCctwSieil
Lri6Fqfz+HtctBSRlSEhRSa7zSViDJ//kJOBLLIyTKhajLl7azl7nO407n7iQaxOK6qsMy9x
gV8GDXwTvQyNFrLlyQ0Um3QKA8/w/NkgKzZNCUD0Iu9eyOOBP9xAiV2m0PQ+R4c7GA2WUeT4
NAUxwjR0fD4z+cvSSLumM+LSnV+DyBDnWwYu91uXVTOVGx+gkgnOnu25chOmWsiru5P7CdNy
qhlj7g61M6sUVSElzYaeiDDe38WhJher75GJhUMYrjIKLAoyCvlLa4jvHwXcVzb2jhErrabA
qiLJMrl56Zi8YYIhHRyX+iqLANy0MBOjIcIdZzgrqdjSsynMdWM1KYhjeDYYJEJeetvOcqIl
ROWW21mUbmMoqGOo6pQu9xLBQPDqTXUdSZ2yhiQRicZIJBIwuaV4CnTTZDLKc4n2dNPd1cb5
k8do6Jkg8fElwcJvSI+G6Gs6RuOojbrNm1hcko4iSyiSGck/hn+ynRgeHSYlN/vqje12jJFR
woYBGISCESwmBZvtSuc9EYCbZmPB5l3s2rWLu3buYHOFhe5BD5G4SMBsCPpjXGjVWbB8GaUZ
9ssFMQ5TBhatidMdXqKBbva/O0hR1bUFMaVUxU/yXvMEsYiHxqYewnE7Lod4CjR7vBf4oMHC
shUlpBDHMxZAtcnIsmgAzYZgMMgb//avvHpg9+XmTsld3+V7txdRU+PixX/8c170WylecxdP
lNghOEz98WP43CvZsTiLjbtW8c8//yE/GJfJnr+ee+6rwXWlIlIUxMxEKBS6fqEe5uKh3eyp
b8ObMJEzfw3bNy+nIDXA3p/8mONjOglNQ5JUlIxlPP61TQy88Te826YTj+vIsoyiVPHAt+9C
3/8LXjk9TiKeAFlBVTLZ/s1vsirr1iyh7+zspKCgAJPJ9Mkrf0paIoFvYoKpvY1Uexoum4qW
iBIKhohpEhaHE4dFRTJ0ItEoumLBblZATxD0+4gkwGS1Y7dZUCdPTg6HQxTEzMS0AUhin0UA
fpscDocoiBGSmwiAkNREAISkJp4CzYDFYvnklZKILMtYLJY5ew8AIgAzoii35tOYz4skSZNP
sebufhFNICGpiQAISU00gYQ5y4gH6G46xcmz7YwnFIqXbGPTsjyuHaYrPHqBfXuOMmi4mL98
FbVVeVgnT/0iALPA1/QuL9b3TL6yU7X+NlaWZ5GY6ODk4WN0eGKYMipZv66WApcVPeqnr/Uc
54cVFi5aTGm2g3h0mGO73+Cif8oby0Vsf2wLBYq4UF8vQn/baY4c7kDJSiNDjtD27nNYcr/H
xryp601Q//wrtKVUkSONcOjAYRyO21lYeKnfkAjALJjob8VasY0VeQAqqdmpyExw6v1jxIoX
sLrahK/zHIcas7lneREDx9+lUc9AAqK+GGQ7UNRUKldsIDs++ab+i7x52oTz8/tv3eJUXHnz
2Hh3Dek5LsxynN7X/4q9I1wdgL5DvBdZxref3Ea65OHg8+/QMzhIZb4IwCwx8PlUKjZVUjml
FsMwFOp23otitWCSIZEWpK9ZB0mhZOWdFEgBGs73Xu7gJStWsksqyQYwEvQcamXxpvk4Rae6
G1Cwp2ZiTwUMjZi3m8MtWdRtuXotY6gL26KvkmlTkciipiKVDzWN2GQhngjATYswPiah+Lvo
DiiYHWm40xyYVBM2hwlDTxD2jdJxYZzswmJUk4Iq21CJIE1bMmOQmGjlXNBNXUYq8hyehf23
S0KSLhXL9LcfZfc+L1uffJL511wy49EINod9ck9LqGoQrzdKYrJ3nQjATdOwuDTOvPM2DZKC
OSWXpWvWsajIhaLHmBjqoKl1BHNuDbWlWZg/qTmvR+lrH8GVX0yK0yqqyj6GFhqn/Uw9Z3wZ
3Pu1zRSkXj9KtdmRgrdjDJ18ZBIEA1bS0yx89NudCMBNc7Lqod9lFQZ6PMTQ6ffZ3zVMRW4q
0mgT5zsT5FQupTw/FfU3OJrjvgH6wgqZeRnYxLfzMeKM9LTQNu5kzcblFKSo058sCmuwv7aX
5o1foVzu50SHD/tyGx9Nay128c3yt3D4ooVFSwpwYBCNJlAUCYww7We7SV2xnaqs3/BMbkQZ
GZ5ANqeTk+kQP9J8nESQvrYT7H2xmQ+PvIsCyGYbS3d9iztzB6lvGaVo/koqMmu5Y+FpXnjm
L4nKZjKq13B/cS7myS9EBOBmWTOxet7mF/+nl0BCwVW0kE235WFVBjj5wYf0nG3krY/WLd3E
v7t7CRfe/D+8354gGIyiKBas1iru/84DVMTHGR4ZwVSwnhSzaPx8LNlB9cpdPFWwno8enEmy
QnqhHZM1j/nVbhxOFbBQs+MrpFQPEMBKZm4+2elXTkiiIOamGSRiEaLRBDoSismMxWxCljQi
gfDVk+UpZhxWE4lIkOhVAyorWJ02VEO/NGKBYr5+hLNb0BdhhhhxBbhpEqrZhnrdMaBiS0mZ
dguzPeW6XysvvZWCyTx3O5bNRaKZKSQ1EQAhqYkm0AxEo9HP+yPcUnRdJxaLzekJMkQAZmAu
TwX022AYBpqmIctztyExdz+5IMwCEQAhqYkmkHBLMwydaGCM/q4uAtYCKorzcJgBQycW8jLQ
08koGcwrK8BpmeYRctxPy5mTdPvAlV9OdXnhVT8yigDMgmD3KQ5eGJ58ZSF/YS3z8xx4Os5y
sctDSANbRimLFpSSblPR42FG+trpmpApKS0nN90KGOiJCJ6BbjoHY+RUlFHgdib9JToa8HNq
/z6GR/voT12OK+tSAGKBCRqPvkvH6ChtsSqyM3OmCUCCwRNv8ubxMewWiLT0EtRuZ83CnMu/
w4gAzIKJrtMMs5gFGQAmnFYVCDLU50d1ppEuGwQGz3HCZGfT/GxGGuppCsmEIirprvxLAdDi
eNpOcmLQQA8kMGdmkysCgKyaySlbRHl5FkfHHJeXS6oZd9ECsiqCGBeV6fdTvIcPPvSy8uHH
WZkj0/rhXhq6L+KpyCHXemkVEYBZEAiozF+5ghWZV5YZRoLKulWYHFZUCSJtIV4fjqIZMhll
i6lTNbrahrk8oo6skpK/gOV5MNLSzRweaWRWmW02ymvmQ+84sufKcpPNSXH1IvCeQ+EGj6f9
/Qy7F3FfrgNVlSgvy6W9LYY/ZJBrFVMkzZIoPq8NpzVEKASyasKsqkiygs1hJhYOMubp4XRj
mNLFqZhNMqolCxsT9E4tdpFkLCluLIQZlxHzg82GaBQpNXvyIJcwmVUCYS/hSBS4dAkQAbhp
USKxXg7+/Y+RZDOphfNYv2E1ldlOot4u9r3wKq1GHouW1VGSlYKocPwMWSwYvgAJwIRBPJbA
abNhs14Z4U8E4KalsvGJP2IjBnosSN+pDzjePkRBuhNnegU7n/oOiYiPnvMnqG9Q2F5XhtUk
UvCZSMkne2wvZwYXsiJHpr1jkHDUTYpdPAWaPaE+GntNlJZnYpUVTKoJKQ5GeJjuMRvZWU6s
FidZWRY8DT40TQdTst/a/uaC4+Psf+klBvy9tEyotJw9RcbCTTy0ROXonvdoHx2muU+js+UU
mWWruW9bCQNtbYScFSwtLmLz+jSef+WXNFgkokYaS9ZX47ZeeX8RgJulmAj1HOX1416iGpic
2SxclYVVmqDjxEEOecPEDVDNKZQuqkCVNRrfe44TfXEmJoKYTA4cjhI2PrQG4+weDrZM4B/3
g8WG057Fynt2scCVvHfEislEVmEhCoUUTi5T3XYUVcGdW0gsrZDCikvLTekpKLKK3ZmKajMB
KnkrdnKneoJun4S7sJLqiuyruqKLgpgZmH6GGIOIbwyPN0TckLE4J0eFkDT8njF8oRgaoFqc
uN1pWBUJ/2gP4+Gp72Ejs8AN3iFGA1NLaFTS8/JJvUWrw74IM8SIAMyAmCLpal+EAIjGqJDU
RACEpCZugmdgrl7qf1skScJkMs3p/SICMANz+Yv+bZBlGVVV5/R+EU0gIamJAAhJTTSBhDnL
MDSiQS+ekVESKYUUZtin7WsVD43S0zVI0LCQkZtHdrrz8jitIgCzIDLUzKn2j/rqmsmuqKYk
04avr5WuQS8RTcKalktFWT4pFgUjEWV8pI8Bv0xefj4ZKRYwDBJRP0M9nfR7whiqk4LKCvJT
LUhiiPRpaARGOzl3/BSd5+vpnPctvruzEtt1tyMhLuz5Na+eGCRiqKTPW8uDd22k1C16g86a
scb3OdZXREU6gAV7YQJdD9LV1EJ/VELHINbVybi2kfXzsvA0H6NhJMCwT0FSXGSkWDC0OEPN
xzjZE0aSQI920jqic/+ORdjF8T8NAy2hY82sYuvmOK+ErdOv5jnNW+cdPPRH/4lyuY83XzhI
S/cg+emlgAjArPAHVVZsv5t1OVeWGUaU0tqN1KSnYpJ1ghf28OpogISehd2dT3WOidTuMS53
zJVk7JmlLCvKJcdlQ4p08cZLHQR1A7voQz0NFVdeFXV5QFMrUuQGq/U2Elq0k3luKzIl1JWd
5VQsfHlsVhGAmxbD53OSmXH1UkmykJ5lAV0j6OniZGuUgnkpmEwKjvwK0hhntGdKiZOs4Mov
J12SAJ3gSB+hjGxSRPPnpsSCftKyMief9qg4nRHGfVHik0NKiwDctBBjg6d5+c/Po5oc5CxY
y13bVlPithL2NPPGT/+FC0YJqzZvYXVJBjcqBZAkCcPQSUQDdJ89QkPQzZb11VjEc7qbYrJY
CXtCGFiQMEgkHKSlmFHFBBmzxcXO7/03dmKgRb20H9rDsQu9ZK2qxJkxny9//78SD47Rcrye
/edk7qgrxTrdVDGGQTwyxsXTjfjMZdy2vpwUUThz06ScEsL7jjK6fhvp0jiNbT7MC1TMk0e+
CMDNigzTPqSSX+jCotpwu1PBp6FHPAz5rKSn2zA73JRWuDl8wkNicTGo15/WDT3OaFcTHqWU
lctKsIkz/yeIM97XwrlT7fgGznHRF+JNbxY581exKidGx3CA9NxSsgrWscXy/3j+xQA5ipee
eDq35+ZevrKKANwsPUxv43kaziTQNJ14QqFseSYWfYLjRy7gjydAAj2WIKdsBaqs03r4FRqG
IwwOTmCxNNHQUELdthoGzx3mXHSM8YHTk2+ew+pdq8gVE2VPwyAeCTA2NIRHLmKBK8b42DCm
QAwjI0ogGMKRMAAXa798L9G9Rxk0Mlm3cTVVeamXfwEW9QA3Tcc/1EFn3wRRQ8GZmU9xfiY2
KcpQdweD4yHihoQlJYvi4jxSzTLDbSfp8U59jzTKl5YQ6zxHr9e4annV8ipct+hToC/CDDEi
AMKn9kUIgLi2CklNBEBIauImeAYSicQnr5REPpogYy7vFxGAGYjFYp/3R7ilfBGmSBJNICGp
iQAISU00gYRbmmEYGFqcaCRCQrZgt1pQZMAw0PUE0UiEOCYcNgvKdL+X6AlCAT+RBKgWG3ab
BVUWY4POqrhvkO6R4OQrlZSsHDJTLGihMQYGvUx2PMTuzicnzQpGgpB/Am9EIs3lmpxQw8DQ
E4QDPrwBDUe6ixSbmVvzJ7DPjhYL0376ACfrD9GTuZmHd22lOA20WIjeC0c4eryec9oSnnpo
OyWZlmu21gl01fPPP3uBix7IrF7HvffvZHGhk48GmxQBmAVjZ97g1WYbuQ4AG+WrNuBymPG2
H+C1A37c6ZfKlHKXbCPDacbf08CF3n66PCrLlq6ipswFuoZ/oIXz7QP09kWoWLWCJeU5zN3x
FmZHLBJjdEJm2YaN2MPpl5fHI2FGx0PMW7sRqdc2/YGsjXDwtSMUfunP+GYlnNm7h4vnGinK
WUXG5I4VAZgFgYjKmnseYe3UghhdQ4toVN/+MNurLVctNySV7IoarKk+bFe9k4KreB5O6whW
8c0AYE9zse6O7dB7mNauK8utaZks37ILvOfo6LvBDDHBTi6qdTw5z4XZJFMzv4ihzhATQYMM
16Vrq7gJvmlx/D47GenX/yUY0HGlX31ZlmSFzLJFVBe4ME9ts8oqqQXzqCnJwDZdd2lh5kIh
pOxMbJIESNgdVqJxjXD4yuNscZ65aUGGus9w4pkOrCYHuTWruX3dYrJsMiM959lzpIt9Fivu
suXcsaWO/DRr0rfrPzOyjJHQrrw2DKwWM6p65bAXAbhpadz+B3/GFsNAj/loP3qAoxfcbKst
ZeUjf8oyHfREiIEzH7D/ZCf3ra/GbhYX3s9EWgbmzgv0RWooscsMDIwTj8o4phRbiADcrHiA
cb+MK92O2ZROSVEWzSNxElqIiC+BIyMFqzmVvJICpHMxDF1HtDx/c7FIhO6mJgKj7fQMWjBJ
Et7CYuZny/S3dzI+3k5vdxynFcbzi6kuTSMw7iFudpOTVs22+Xt56fWDbCiVaG0cIHX+BjKd
4jHo7IkOc/54L+ZUC7IexzvmI3/BfMyKjwvHG4m5HKiSRmhsmKyS1agK9DfV0z0RprfXg9U6
wtBQPlV1ZRi9F2gd9jPcPYgxMMJofxZlS5aQZ0/ewEQDAY6+9Rbdk69P9rZiWbSLsjUmzux7
i8bJuopjox3Yim+jqKCavq5WAq6F5KS5qbrzEWpf/BX7DsoU125idV3ZVQ8eRD3ADEw/QYbO
RE8DjW0jhHWVtPxy5pXl4TSDf6iNppY+/HEJZ1YJ86uKSDFBz9kPaBmb+h4ZLN64AL39BA19
U6eOsVO9Zg3FzlszAF+ECTJEAGZAzBBztS9CAG7NU4sgfEZEAISkJm6CZ0CWxfliKkmSkGV5
Tu8XEYAZsFpvMABrkpJlGYvFMmeL4kE0gYQkJwIgJDURACGpiXuAWaBFA/hCH5W9yJjtDuxm
BT0eJhCMok/+RbWl4LQoYOjEYxGiCQmL1YpZlcEwMHSNSCRENHapy7TNYceiymKGmOkEhznw
/DP89SuNkwsMEgnY8oN/4nub3FNW1Og//mue+duXaNNy2PjQ4zx65woybZdKYkQAZsHw4V/w
dx+GSLcCOFl0xz3ctiAHb+Nu/uGVTizOSzu7ZMPD7KrLJzp0kfPNjZwdUFi3ZjNLK9MxDI3x
7jMcPnKKtgEfmuykZPUOdq0qwSyO/+s5stn45A/Z+OTk6/ggu599ibxa99XrhZt5+aUedv3w
n6hTW/n1Syc511rIxkUFgAjArAhEVHY8+X02FVxZZugaWlRjyZf/PbtqrvQ+MbQEnvExLCWL
qE0L4bi8vk44EKFgzQNsK3Ih+Zp44ZU2/CuKybhFxwa9dehMNLxLe8l27kq95k+dx+hb9CDf
KnQiU8OGklYaw14i2qUvS9wD3LQEPq+NjIzr/xL0J3C7r675khSV/MUbWFGZjWXKgS0pJvIW
rqW2NAOrImMkEtgzXeLs/5uID7D/aJx1qwuvO6ATvgncRQWTy81kZBoEQgnik2N5iSvATQsy
1NNM40+f5aBqI6t6OZtWzMdtlRjpbWZf47OctVpwFS9m8/ol5KZYpi2IkSTpUltfjzHcepbG
oSiVSxfhEGf/TzTecJiBvFq2ua//PUKSZDRNv/zaQMVkkpHENKmzxcH6J77F0riBHvPTefY0
R5pS2bKkmMX3/D7FEdC1MMONx9h3ysV9ayuwmaa/8BpaiO4LZ2gfM1O5eBl5Lpu4Af4k8X7q
G2RqV+djnWZGHcXlZvR8B9rmRShEGOiNYSmUMYkZYmaJpqE6s8i1mZANnSxtmJf7QsQTMczW
DHLSLSiSQY5lgoYjfvSEDtMEwDDijPQ20jGSyvKNC0hRJHHwfxJDY7zxHMG8ImrzMpEn95ce
jxCKaZgsNiyVW1n+i7/jheNPslxt592BCKsWZWMXM8TMEn8L7x8Yp6A8E6sRpiquvqgAAAyT
SURBVO/iMFlVFZiVAepfb8VZnY9DTTDW1kJqzjpkRcLT08RwMEBf3yATE3ESiVzyStIZuXAa
T8p6+lsvTr65k8LqApyiGTQ9I0ifz0lZTh4ZDvly0zI63MwH5wepWLqZBbl57Hz6dn76f/+G
/y0VsPX+L7OkPPPyjPKiHuCmaQw3H6b+dDd+zURW5VJWLi7HZZXwdJ7i6MlWPFEZV1ENq+qq
cVugef+vOdk/9T3yWf/AKkJHXuFU/9Svo4DbHtlM4S06RdIXYYIMEQDhU/siBODWPLUIwmdE
BEBIauImeAZ0Xf/klZKIYRgYhjGn94sIwAxEIpHP+yPcUnRdJxKJoGnaJ698ixJNICGpiQAI
SU0EQEhq4h5AmLP0yCin3nuRf9tdT3/ETO093+b3HqjBfs16vva9PPuj52hO5LP1y49x38b5
pIi+QLNn+NBP+ds9/ZOTWqSw5O4H2b64ADk4wKn973Do/AAxSy5r77mHteVu4uN9NJ0/xrFe
lXXrN7G41IWhxeg7+y5vHzzHsE9DSSlk7V07WVeRgSL6BE0jREfTaTq98/j9Hz5GjtnH/r//
a3Zf/J98pXrKavFOXv7no9R993/xLaWF5988ypk8N2vnZQMiALMiGJG54+k/ZcNVBTFxOs/s
p9O2hm98twqHHiYiWZB1jdHOZsLZC6hNjeGc/B3eMCSs6WXc9eQ2su0KscFj/MsHzSwrW4tT
EQG4no3ypVspWyIjy4AmUVFVyplrG/Wdh2lb8CUeL3Mhs4SNhT20Bj2EdRGAWaLh91lJv2aG
GMPw0t2rUnfPfNIsAE6ck38rXn47xUxw9mzP5fVl1URm6XzAQIuF8Ech250qbtJuSJqsoTCI
+/tpON9Of2IRq0uuXkvzenGXfFQoYyErR+FcVCchCmJmS4jRgT5633mZNsVCWlE1S+eVkGL2
MOKTMY6+RZM/hpKax8KlCylKt3Ojzp2J0ARt5+tp6I1ic6ZTWbsQq+gJ+jF0QgMtnGzuxGdk
s2L7ErKvG6fXgGtKkAzD4KMOcOIEc9Ms1Gy/g7rKSsqKstB7z3GmfYSopmFIZlyZhZRVlJGj
jFB/uoNw/MY/GskmC+7cUiorS8hNidPf70UXXRVvKDbazbnmDozMhWxcv4Qsu3LdOkqqC093
7+TIHFFGh3XsVkUUxMweM7mVC8nFwNB1oqlRdvf7iMUzyU3vJqumhnxFQo87GHyhF29cw2G+
/osCkE02sornkVmoE48OcfjFs/QszaNMnn795Bamd7APfyyPVfMLcKrS9HOvla6m9F9+zb6e
P2SVcpGDvX6qylzYREHMLBk/w2v1GouXFeEgSPuFQdIKi7CY3ZSXBqn/sJl1CzKJD7Tjz83H
pcqEfWOE4j78fj+GMc7YmIzVGaH9ZA/2ogJSbQqxsXa6oyrzxJR604vHCPSc4sWffcg//vTS
IsXqZMM3/pInSrp483Qf1Su2szi/jAeeqOXv/vIP+CnF7PjK49RW5oiCmE9j+gkyEgyce58P
jnXiTZjIXbCSjcvn4bYrJMIeLhz6gOPtHpT0SjZsWUVJqonz7/wjh7unvkcx27++AfXCMerP
d+IN6ahp+ay8bTOL85y3bGnkF2GCDBGAGRAzxFztixAAcRMsJDURACGpiQAISU08BZoBm832
ySslEUVRsNlsc/YeAEQAZuRWfRrzeZvL+0U0gYSkJgIgJDXRBBLmqAQTvQ28+/JrHG0fJa6m
U3vfN3hsfRHXdhzxdx/gF//wKm1aNut3PcCOVZVMzlkiAjAbxo7+kh+91jT5KpW6+7/KztpC
THEvDQde4a1DHUSsBWx+8AHWVWRA2EPLqQMc7FZYt2ETi4rTprybxsj5D3j57R4WPf4Aq3PS
xGV6OnqcYCRORs1OnrorAzU+wPs//zHvlf8F2/OmrjjMO//0Fml3/g5PKe28dfwQDVluVlZe
mklGBGAWeL1Bbnv6v7K1eMpCQ6P7+OscCy3mG3/yKGl6iKBkQ9bitB9/jy5HFQsqdayxKWPq
GAax8U7ODYSwYkZm7g438lsnWcmvWE5+BYBOIpLOknl76A1fs17LXuqLHua/rV2ATBla76t0
eAYJaSIAs0TH57WQ6ZaY+jBE1320tyVYfX8dmTaANFyTf6va/GWqGOfkya6r3ykRpLujH7O7
kJKCfnHm/ziShEQUT08X7e09DI+2067v4NHyq1fTJjxkVZZPlpXayC8y0xQ3REHM7AkxNjSG
59h7eBQzqTmlVJflYVeGGfanYGv+kA+CMVRHFuXzKslNtU5fEGNoBDy9DPoVimrLGGvrF+f/
TxRjrOciJ+svEMuvZF6JCS0OTPlZQtc0FOXKXYFEglhcu1xnIU4yN02lZEUtGRjosSC9DUc5
3TFKTE8Q0xLEwnF0Qyc01MSBUx1EblAQo8XD9LV2YSmqodAl+v//ZlKoWreLb/7gu3zjnpU4
ew/wdlPgqjVMqWl4evsnC2JieMZknHZVFMTMHiuVq7dSiYGuxQk07+eNoXEWF2WQ63ZQtnYj
hSaJRLCZl18aZCJegX2agpjY2DnefXM//oxmDisavkEPRncTwYe+w21l4mu6TjRAf3c7HkcJ
83JSsNht6P5ORr3XdG4uXUH+v75Mff+3WKq08WGXl6LCVKziKdAs8ZzkteN21m+uxEWInu5R
zGmlmEyZlOWPcfRUP1nL84gNDRFMTcGpyFzpgW4AlwaYtWQu4ZFvV0w2e4I0vHEMffUy6vLF
1WBaEkSGm3j++R/R2DOOYXKzZMdj/O4KB8Guo+w+0cv81TtZWjCfe3ed5Jn/8CT/S8pj0wOP
c1dFLqooiJktCbrqX+SlvY14EhaKl29l15Y6cpwq8eAQx996iQ/ODSFnL2HXg7czz23myHM/
5O3Wqe9RyVf/9BEWWj+aaCJIwxtH0VfXsTDj1n0M+kWYIEMEQPjUvggBuFVPLoLwmRABEJKa
CICQ1MRToBkIh6/9nT25aZo252eIEQGYAfG84HofzRM2V4kmkJDURACEpCaaQMKcZWhRxvtb
OXviFKHS7WxfnINpmh/OQ0NnePPV/fRpbpas38zqmkJsoivE7PE2vMVzBzonXzmYd9sO1lVl
oyYCdJzex6Fz/cRM2SzbehtLC9JI+Ho5dfAADf0B5LRS1m9ZR1WWAz08TvPxDzjS7MFSuIwd
m5aQ6TCJ0UGnFWe44wz1xztxKeN0eKJoxlUdQSd5OPirtwhUraVWGuLssSOkp6WweLIISQRg
FvjGBila/yVW5wHIWJ0pmCSDkeb9HO5LY/1dK0kxYhhOK0YizsXDHxAuWsddK1OI9Z3k/RPt
lG6txtN1hovePLbcvYLxMwfZ15DLAyvyUcQcAdNQcRctYmt2DZbePbR5btBnqucQH5o38Me3
r8WBD8tL7zAwOkRVoQjALNHxeU0U1maSmTplqeajrXGMpXfcTcWU2WMMw2Dhjkcn+6gbJFLK
yRqNo8fjjPYOUrL6YcqyZcpcy2nZ3U14eR5OcQ2YhoTJYsdkAVSZG43Moo/041p4GykmGXBR
Ve7gQEInLgpiZkuE8bEosZ4GGmUVa1omeVkuzPIwI6EcXJ5mGvs1ZGsKOXm5uGwmFEXB0BME
J0YYaBvAXVaDJMlo8RTc7snnEvZsCulhHOPy1ErCzGmJxDUDd0UIhuJok5WoIgCzIL3ITUvL
RXwGaJKVidpVLCyIE4n4GLjYSiAaR9d12jzL2LasBIsUZ3yoi47OcdScapaVZKDEQxiGfFW1
mBSPk5i7j9hvCSank4nWEQwKkUjg95lISzOJgpjZY2fhtvtZiIGeiDJ+4SD7+j1UZKeSke5i
wZat5Fok4t5Gdr/Th7cmD3uok4tdUXLL51OQnYZJhkRCRjEF8Pp0SJch6mXUkkrNHB517ZZQ
uAjXK+9wbt0jVMs9HO/2417hwCKeAs0SbzP7L1iorSvCSZyJiRCqRUZVMinJneB86ygZCzJJ
BILE7TbMhsFgcxuWiq0U59gun/EVVSbVbeP8uXbKVuczceY0vvSFOEQAbiBM16m9PP+L9+kP
jdAfe4czL6dRseNpnl4UYn/jMGWL11GdvZA7Vp/lV3/1nxmXUqhYuZ21xTmYREHMzE07QYYW
pOng67x7tB1vwkT2vJXcfttKitOtRMc7qN+7lxPtHmRXBRvu3MrS3AR7nv0bjgftl78E0uv4
xlO3kx4a4Oh7b1LfMo69aDl33rmBCrf1lh178/OdIEMnFg7gnQiSuLxMwuR047bqBKMJzFY7
FlVGiwWZGPcTQ8WRkorTZkaWxAwxMyZmiLnaF2GGmP8Pz4FqemgpvIQAAAAASUVORK5CYII=
iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAAA7DAAAOwwHHb6hk
AAAgAElEQVR4nO29eXxU9b3//zyz7zNJJslkJwkBkkDYEQIIKAKiVatVtO2t3by9117bx71t
f10erVVvv79f2+td2t722/Z2s16tVIFq3RBkl30JkASyQPZ1Jpl9n3PO749o0EqUxJYw5jzz
35nMmc/nzHmd+Szv1/styLIso6AwRVFNdgMUFCYTRQAKUxpFAApTGkUAClMaRQAKUxpFAApT
GkUAClMaRQAKUxpFAApTGkUAClMaRQAKUxpFAApTGkUAClMaRQAKUxpFAApTGkUAClMaRQAK
UxpFAApTGkUAClMaRQAKUxpFAApTGkUAClMaRQAKUxrNWC/E43Gam5uvZlsU0pBEIoFOp5vs
ZkwYQUmMpfBBOHv2LHPmzJnsZkwYZQikMKVRBKAwpVEEoDClGbcAQu46fvKPn+TbP/kz7dE3
D555gr//f19jaMx3xbiw/yl+/dRLtPuu5P/TDZHhlr088R//h4e/+z3+7zOv0+YXJ7tRH3o6
Ozv5/ve/z86dO0mlUgAEAgFefPFFwuHwFZ1j3AKQxBhibIC2rjaO1nWRkoGYj15PiNSY75JJ
RPz4fEGS0pX8fzohEWo+wAvHg9Rs+hKPfOef2TAtztGde2gPSe/xvmH2PrsLt7IGMSFSqRRu
txuDwUA4HCYYDAIgiiKhUAhJeq9rf4kxl0HfC31OMfOLcwlcaKR3Th7Fb70gxnAPeEhqHeRm
W1DH+mlsg/JK+0Q+Jj2Qg7R2ilQvXEB1vhWVACVz5uMWz+Hu8VFcJNIVMVOcZUSQk/j8IQAi
3nb6PH1oGhoYMljILZxGhmGS+5JGxONxent7mT17NoFAAK/Xi8PhACAUClFfX48gCGRlZVFS
UoJGo8Hr9dLe3k4ymcTlclFYWDjBOYBgZtrsEvB3caFj6NKTPOHh5N7X2XuyiwTA0EF+/j8H
8f01enytkggypDGRaTSjFUYOqUwmTDoDcjBEqu8kfz7ZN/JC0k/z+bM0Xeyht62dvqE+muvr
abrQgS82eV1IR8LhMF6vl6qqKrRaLW63G1EUkWWZoaEhjh49yr59+9iyZQvNzc2EQiF27NjB
jh07OHDgAOfOnSOVSk3sFwDAlFdJ6cAJDjW3Mc95ZT83U40xBzcGF4tuLCA87KDqY2vIFoSr
2awPBd3d3Wg0GrKzs8nNzaW7u5vq6moEQcDlcrFhwwYyMjLYu3cvTU1NAPj9fh544AHsdvvo
Bt6EBYDKRtWyWez+TSMt865swvGhRGclKxVhOBqmSLajE0CKRIgkYqiclg9wgRXei8OHD7Nn
zx4OHz5MKBTCbDazdOlSjEYjer0ek8mETqcjLy+PgYEB4vE4VquVjIwMVCoVGs3IN/MBlkEF
jAVLWJpznp1H+y4djoYJhsJEY27OHDr7IVrpGQPByvRiNQ0nTtLQG0ROhek4e4q2fpnsAgcq
lYpkOEJKFvH2dXDhQjejox1vLz0RCUlKISqLRldMOBzG7XbzrW99i69+9at8+9vfpry8nL6+
kfswlUqRTCbxer3s2rWLvLw8nE4ng4ODtLe3E4vF8Hg8ExsCqdQG7FnZmLSAysLyj25k53d+
TX6pBY0hi4pZWRz4zeP80yulbLiljOlOCxoEdCY7DrsFrQowOMj/0DwdVZgrVnCbcIA/b/4x
W/0y+ZXL2HDzakrMKjAtZuWxJ/neo1vJKCwlp6AIu04NZDBnmZVfP/4IO11VrP/ofczJmey+
pAcDAwNUVVVRU1ODSqVClmVWr15NZ2cnFRUVDAwM8NBDDwFw2223sWzZMnQ6HcuWLeMHP/gB
fr+fjRs38rGPfUyJBVL4YCixQAoKaYwiAIUpjSIAhSnNmHMAxRCjcCV8aA0xytz43SSTSZLJ
5GQ345qitbWV6dOnT3YzJsyYK5GCsjt5WZTr8m7S+ZoocwCFKY0iAIUpzbg3Y1MRL0e3/YRn
jnhGj9Vs+g6fq80kNtzJ8b072ePO4GO3rqeywAqyRDwwQP3hnexqgJV33MyiMicaZJLRYVqP
72XHHjczP3YrqysL0P9Vu3e1EAl0nuHAwdN0h8A5rZqlSxeQb1FPdsM+1PT397N9+3aqqqpY
sGABarWacDjMqVOnWLhwIUaj8X3PMW4BJGMh2jvbKV/3z3y0ZiTO35jpIB4YYufm/6E1ZqMn
FGU4MjJZTIW9HH3xtxx36+jqh75AbCRKMhagaedmnm+NEe4J4RiOkK4xpcne07x2tIe8OatZ
lKWi7/wZjh04wdI1S8gdU9F+TuxsouzGxWSk8Rh6shBFkaGhITweD263m0gkgtVqJZlM0t/f
P+oQez/GL4BEL0NDevKLyykuNo0el+Vsbv3H/0Pw/Gs8/nLr6HG1OZMVH/8mK3qP8Pjvj146
kd5G9a3/SHXwPL9//OX0HYvJIVqa/JTULKCmIh8d4LRoSZ5tpqcnQE6RhkBSi82oQUAiFk8A
kIp58Xg8WD0eJI0Os9WO4cMRHHVVSCQS9PT0MGfOHGKxGMPDw1gsFmBktc7j8RAIBDAajdjt
dlQqFbFYDJ/PhyRJWCwWrFbr+AUgin78gyGk5lMciuiwZBdRXpKDUaPics+xMVcIBOGy/592
JIMMaa0Uma3o3uyTYDZjNhiJBoKkupvY3FbKA2umQcJLw9km0JiJdNVzpqWLFn8XDmcRS1Zv
ZEbWJPcljYhEIgwPD7NixQpOnz7N8PAwhYWFyLJMT08PTz31FMFgkOzsbO68805cLhe7du3i
0KFDiKLIddddx4YNG8YvAJ3Jxcy5NbS3vcH+5hCDARMr7/s8t9VkwVT8KZckRFl6l/lFkGVG
/i6DsZCVt5UgyGeYddv1OKfidfuA9Pf3A5CTk4PT6aS3t5eZM2ciCAK5ubmsXbuWzMxMdu7c
SUNDA6lUit7eXh566CGysrKIxWITM8SYM2q4+ys1gEQq3M8r//0dXjvVNSKAqYjOjENKEIxH
Sck2tAJI8TjRVBLBbvqQhHxfe5w8eZLjx48zMDCA1+tFlmUWLVqEXq/HaDRisVjQ6/WUlZVx
5swZQqEQDoeDnJwcVCoVWq0WmEhalJY32NvYTzgpIyd8eIYlDMb03Qr/wKisTMuRaW48x0VP
GDkVpb/5HN0ekQyXDZVKQIzFEGWJ4FA/PT2DxN96b2AIT0xCkkTFEDMOYrEYPT09bNy4keuu
u461a9dis9kYGBgAQJIkRFEkGAxy7NgxsrKyyMzMxOv10tfXRyKRwOfzIYriBB5QGmh88lF+
cX6QmGSi8LpbeXBNKf7+1/jPB39OXSKCN5zk6K7tGMvu4vGH5/Lyw4+yqzuGNxBDu38HT+iX
863f3s/F/3yQzXUJAt4wwtFdPGss44s//zHrctNpSKDGPn0Bi+NvsPsPP2NLGLJKqlm+5nqK
rBowzKJy/xb+7QcvYMtxYcrIIQ8AG2UVSZ760Q8wuGZywy13UZ09yV1JE3p7e8nNzeWGG25A
q9WOhu1cuHCB4uJiWltbeeWVVwBYsWIFCxYswGw2U15ezve+9z0ikQhr167lrrvuGr8h5mrE
CF2rW+uJRGKM5TWZy10WQRBAvvw8QBCEv7iWQlpOoVpaWqioqLiqn/n26/bWvTLR+3LcvwDX
6s05ubzHzfseq13KtZwYl7tuE72Wabv8rqDw10ARgMKUZsw5QCKRoL29/So359pGlmXFJ/EX
hMNhzGbzZDdjwowpAEmSSCQSV7s9CmlGc3MzM2bMmOxmTJgxJ8EqlQqDQcnWqvDeCIKQ1veJ
MgdQmNIoAlCY0ow/GjQWoGH3ZrbXX0p6XrHu89w+28zghWPs3nOcnqCEvXQJG9ctJs+sJRke
4sLZIxy7CPNXL6eqwEEy0M6ezc9y9h250yu456u3U5J26+MSob7zHD9xnoGITEbBDObNrybH
pDxf/pZ4PB4OHDhAeXk5VVVVqNVqIpEI586do7q6+oqGZuP+hpKRAA2nDhDNmkNtbS21tbXM
yjUQ9bex76W9RLOrWDxvOrHTz/LUvk7EqJ8zr29m97EGjpxo4II7hARo9A7KF9S+eY6llIjn
2dM2TDqOJpP9Dew63ETcUUzVzFIM/laOHDqN5z3XEIKc3V+HX1lVmhCSJNHf3099fT1tbW1E
oyP1uuLxOC0tLVecvWP8hpikG2/AyIybV7B8vmX0eCqZy6pNX8DsdGDSSFg6t/PDxjbUG6ZR
tXoTZX31/GLL6dGwAI3eQcXC5VQAxFv43+ctrLp9DekXDhOl/VwflmnVLKwux6YViOfbOFp/
ka6+EM4SyxjvSzLcP4zrqrb1w0MikaC/v5+ZM2eSSqXw+XyjhpjxMAFDzBDBYRFreJiubj86
k51MhxmNxk52HshiHF/nMfbXw8J100FQY7I7MYUMaFSXGdrIKboO7GSfaiYPLcgh7WwySS89
KjvTsnKxadUIAuid2WRa3UQ9XpKpN/jFhel88aYyhISHoycbkVU6Bs4e4o36Hl49vYuM/Bnc
dOenmK+o4YqJRCL09/dTW1vLmTNn8Hg85OXlIcsyLS0tfOMb38DtdjNnzhw+85nPkJ2dze7d
u9m8eTORSIT169ezadOm8QtArTVjNRk59sd/4zgysr2SO+//BKvK7aSiXi6e3M1LO48TnbeJ
L6wsel+TjBTt5OipbsrmfIQiqzH9AsJSKZKiiCQIvKVdAQFBkhAF6fI+Z8t0bvv8TOzP1ikV
YibIwMAAkiRRUFBAV1cXPT09o4aYvLw8Pv3pT+N0OvnTn/7EiRMnqK6u5vz58zzyyCO4XC4i
kQgGg2H8ArBmL+PB/1oGSCT97Wz5z8fYenAlK4tLadq/jS37+yi/6VPcet0MHIb3y4qQxHP+
NI2hbJYuKMeiT8NJo96MHZFoIoYo29AIICfixKUUaotRMcT8jairq6OxsZFt27YxMDBAIBBg
8eLFaLVaLBYLDocDo9HI3LlzOXXqFF6vl5ycHIqKilCpVOj1I9kKxn3HRTpPc+LiENGUjCAI
CGjQagQi3gb2vlKHa9UnuGNF5RXc/CBHPZw91YSUU86Mwkw06fggVNmYlpGkqbmJDm8UWYwz
eKGZHk8SW54DtSAgxuNISIS9bvoHhhmdnoWGGU7IyLLIFVb1VODSRPetlIxOp5NkMsng4CAw
kjFCFEXC4TBnzpzBbrfjcDgIBAK43W4SiQTBYHBihhgx4ePE1ud4uj9AMimjdS3l7tpion2b
OVJ3nmToP2j485t3cs0mvn9XFtt+8jOOdPto6/FzvKmeXbYlPPSjz5LT18aZLj/T1lTjStsc
OlqcM2uYFTnMgWd/w8sJMGcWMnvJMkocOjBUUL5/Oz/76W5MNiuixooTACvFRVGe/+V/czC3
nOU33qKY4q+Qvr4+srKy+OQnP4nBYECSJF5//XVaW1spKCigo6ODRx99FIDp06dz/fXXY7fb
ycvL4/HHH0cURZYtW8Ytt9wyfkOMlIwR8HkJxVLIqNFb7WTaTJDwMzgYeGfxa2MmhRkavIOD
hN/5AjlFTjTJKIFgBK3ZgcWgSbfp79uQEeMRgqEICRE0eiMWixmdWgBZJBrwEYyLqLU6NBot
ep0Bg16NGAvgDcRAo8diS8+0KJNRISaRSBCNRrHZbKM+gFgsRjKZxGQy4fV6icVGKrFZrVas
ViuCIBCNRt+RFsVmsyklkhQ+GEqJJAWFNEYRgMKUZsxRZzKZHK27qqAwFqlUis7OzsluxoR5
Tz+A3W6/mm255kmlUlecdHWqIAjC6Jp6OjKmANRqtSKAv2DstChTl/7+fqxW62Q3Y8IocwCF
KY0iAIUpzbi3XqREmLa63Ry7GBo9VrjoFpYVC3Q2HKf+4iBhUY2toIplCypwGNSkYgF6L57j
fB9UzJ3NtGwLKmTERJjBjhbONQfJXVDDzDxHmsbOSESHu2m90I0vDpasfErLinGkY2xTGuH3
+2lsbCQvL4/i4mJUKhXxeJyuri6Ki4uvqHzr+A0xYR/HdzzD0Y7IO44n4h4unGvDHxUR4wMc
ff5/2Xq0FykeoungC+zcvYdtf97DmR4fIkAiQtfJnbz4+m5efu41jrW5SdcCpKnhNo6eOEuX
N4YsxvG0NXDqzAX879mhCBfPthJS9iEnhCRJ9PX1sWfPHhobG0d3fqPRKHV1dcTj8fc5wwgT
MMQM4Q2bWfyxu7l3waXJj5hSs+CmOzA57OiEMG/4v8YfWgf4zPJcXBVLWG1vo9fbdClPplpH
Rskcrrdmkuo4giZt74MYvc1dJO3TWDJ7BlkGgXB/Cyeaeuj2FGLPG6tOVZzeiz3YZpczfhuH
QjKZxO12U15ejiiK+P1+TCbT+7/xLxh/MFxqmGhYR6HlncmQ1BoTmdkmpFSEvtM7eLXBwYov
FCGodTiLZ+JUezG8PdxTrcWeV47dnOCwNo2HCmKQXtFMaUEBmUYtggDm3Dyc/QESHj8psY4t
XYXcs7QQIemjvukiyNBVd5gj5/vYVX8Au6ucNbfeS03uZHcmfYjH4wwMDDBnzhxaW1vx+Xzk
5uYiyzJtbW089thjuN1uli5dyqZNm7DZbJw6dYonn3wSv9/PunXruOOOO8YvAFlIEejp5tdf
v5PfaU1kz97AFx64k7kuDR2n/sRPH3uGNksJq+66l+tLM/4Wfb+2SMSIiBKCSjVq5hFUatQy
pBIJxGQUf/TNpVNZJB6LgXUmG/6uDOsLIxVilCDQ8ePxeIjH45SWljIwMEB3dzelpaXASHj0
Pffcg9Pp5LnnnuPQoUPMnj2bgwcP8qUvfYmCggLC4TA6nW78cwBH3lq++9w2tm3bytM//zaL
w6/xu50dgJ5pC+7l37Y+y+8ef4Ds+qf44QsNf+1+X3vojFhVkEylkN4cxsmpJEkkNO/hOHq7
CUwQ0jM1+mTS2NjI4OAgdXV1DA0Ncf78ecLhMIIgYLVayczMxGw2s3TpUkKhEG63G5fLRWlp
KQaDgaysLDQazfgFEB+8QHNfgLgIan0GOZkmIEky0EN7r5+4pMacXcrschs9ve6/QdevMdQ2
Co0xLna2MxCKI0tJfN2dDHjjGLPtqAWQkkkkZGJhPz5f8FLIeDREKCUjy5JiiBkHyWSShoYG
4vE4R44coaOjg/7+fjyekdrVb+VwjcViXLhwAZPJhNVqJRKJ4Pf7SaVSRCIRJEka/xAo7m1n
/+sv8kI0gRQLM5So5OaFRcR9Dex9/iTuRBKJFGGfiY9smEk82DGS/6enn5PnBrjoG6J5x3zu
enAVAy/9ioMtXs43tCOEhuk6WM7GBz7DXEc6PQ515MyYTvapMxx5rQ1ZEFCp9ORMr6EwUw/6
QvJ9dTz/pwa0GhlvTM2MIgAjuRlB9j2/jeysfGYvWEaRsvF+RQwODmKz2bj//vsxmUyIosiO
HTtob28nNzeXvr4+fvOb3wBgMBjYsGEDmZmZ2Gw2fve736FWq6msrGTlypXj9wOkoj562tvo
90UR0WHPK2Z6oRN10k/3xXYGAlFSqDA6Cqgoz8coB2mrb2Aw9vazZFK5eBqh5pN0+d9+3ET5
wnm4DNemAN6rQkwiNER//xDhJBismeTkOjFrBZATeHu7GQgk0BpN6I1GrGY7douORKCPjl4f
GKzk5hViS8OQmsmoEBMOh/H5fOTn548aYnw+H9FoFKfTSXt7Oz7fSMa1vLw8XC4XarUar9dL
R0cHyWQSl8s18n7FEHPlKLFA72YyBPDXJI3XHxUUPjiKABSmNGNOglOpFENDQ1ezLdc8oigi
Kcs170CSJIaHhye7GRMmPWPPJgm1Wo1ana7pW/42CIIwWnU9HRlTABqNhtxcZW9e4b0ZHBxM
6/tEmQMoTGkUAShMacZviEnFcbfX0zpwaWcrq3wBM5wCnq4LdA0EiMkCpswiZpS6MGlVSMko
wwM99HrBNa2IbJsBlSyRCHvpbm9nMBAHQwbTKsrJtWjTsIK6TCLoobfPQygJRmsmrryckY0w
hb8ZkUiEzs5OMjIyyM7ORqVSjYZJ5+TkoNG8/+09fj9AaIi9zzzOq74qKnNH6rlUmKuYZg5Q
t/d16t1xkmIYz7CG6+75PHfWWGk/+TqHTp5lbwPc+sD9bJxXCIkIrUde5OXjfYiCTMwbQJh7
J//PpkVpVyVGDPRw8vhJOgbCI6EQagOuGfNZUF2CZcwrHKOnxU3m9EKMaSf4yUeSJDo7O3n6
6adZtGgRN910E0ajkVAoxL59+7jllluuyKw/fgEkvPjjNtbe92U+vtD2tuMqqtfcTa0rB6Pg
Y/d/f5NtZ7q5s6YKrSWLWZXVtLo7RvPlywjoM0tZu+kjVBZZiB76FZ/6n8P0b1rEtPE2alJJ
0H++iUEhj9pbaii0CHjbznK0pZlOVy5VuWPJOUJrXQtV0wsZyzKjMDapVAq3201ZWdmoIcZo
HP+VnFCFmHBQS67lne4brc5OQYkdKRXD3XySEz0O5i3LQdAaKZ69nOKew+w+fCmBkkpnYlrN
8pFlRSlMW+8A6syK9HNHiX66IgYqppWSb9UjCJBRPA2XJ0J4wEdK6uGVvnxune9CSAVoah25
Br2NxzhwqoNjffVk5JRQu/Z2Kp2T3Jc0IhaL0d/fT01NDe3t7aP5/wG6urr40Y9+hM/nY/78
+XzkIx/BbDbT0NDAtm3bCAaDrFy5kvXr109EAH46TtXx8lfu5klbBhXX38uDn1xNgUWi4+Sf
+Oljf+CCsYAVd3+aO+blwxg5nwVBQK1WI8UHObL1t/xmr4rPPrSWzA90WSaBeAS/KODU6Hir
ApSg0aIVVMRiccSIhw6PY+QFKYHfN4xsmc6iG1YTCZ2lfMNSnFo9ZtuYn6BwGfx+P6FQiOnT
pzMwMEB/fz/l5eXIsozRaOT666/H4XDwyiuvcOzYMaqrq9m1axdr1qwhPz8fGNnXGbcAMgpu
5T/23ApIxN11/M/3Huffny/iPz4+i5L5m/jhljsJ9p1h83//kh+mvsQP767mciKQZYlIfz1/
euJ3HE8t4EuP3EF1rjn9aoTpDVg0ArIkIssjRhdZEhEFUGu1XHbbTKXDmmHEYrKSlZODU5kD
jJuGhgZSqdTo0KepqYl58+YhCAJOp5OqqiosFguyLHPy5EmsVivZ2dmsWLHiHYss4xZAKjCA
W7KRbTegs5dRPd1BSyqCGB3GGzfisBmx5s9h9eI8Xm7uAqovex4p5uP4jj9SJy3k7//hHiqd
abqbqLZToA5xvrcLe7aFbINAqK8Hty9CdpUDTRwkMYWMTDIWJhSOYnjraZ+IEhVlZLUMqBRX
2BWSSqU4duwY3d3dnD17FkmSkGWZG264AafTiSzLSJJEMpmkp6cHrVaL2WwmkUgQiUQwGo2k
Uim0Wu34BRDtOcNrxwfR6dQQGaSxN4/ltQVEBxvYsbsT2aBBRZS+8xLXLy0jGRmgbvceLvZ0
0NLagff1l4ier2bpjVnUHT2NP9NF3c4tnAagkDWblpObVneCgcLKaVw40sihPf1Y9QKxYBht
7iyKc0zgzyXL28ju3T2QDNA+GGdG3sj7Mg0eDu7aTVGmk/KZc3Glb4bBq4rH48FkMvH4449j
tVoRRZHnn3+etrY2nE4nbrebF154AYChoSHWr18/6gnYvHkzJpOJoqIiFi9ejPqRRx55ZDwf
rjKY0cb9BCIJZH02c1atY82cPHQ6PUQDhGIJJMFAQc1qbllegV6O0tfejk/loLS8hFybAQEr
02YXYNfYyLCb3jbosVI6uxhLWgkAVKYM8jKNpCJhoqKGjKIKZleXk6EXwOjAqY4wHBExZeRR
Wl5GUXYmFpMJW5aBiDcEOgtZOblY3j+P0zXHZIRCJJNJcnNzKSgoQBAEVCoVGRkZGAwGsrOz
EQSBeDyOVqtlyZIlzJgxA6PRiNPpJBgMIssyLpeL3NxcxRCj8MFQKsQoKKQxigAUpjRjToJF
USQUCo31soICMBKS4Pf73/8fr1HGFEC6d+xvgeIIezeiKI7m40lHxhSAVquluLj4arblmkfJ
CvFuQqEQeXl5k92MCaPMARSmNIoAFKY0488OLaUI+9x4w5eGAsYMF1kmFbHgEJ7ApcIEGms2
LrseWUoRDQUIxsDisGPWaxCQkSWRWDhIMJRC77BjNU4gW+81gYyYiBIKRUlIMhqdEbPZhE6d
Xht66UYymSQQCGAwGDCZTAiCgCiKRKNRTCYTKtX7303j9wMEB3n1p1/mDy1OChwj8Ts1m77D
Z+cJHP7Dv/LveyOUZY/UDsi94UG+ecs0+poOc/DAfl6pg9v/4TNsnFeIVkwy3HGaA/v3s/PV
fuY/9AD31VakZWy8FB2m+cwx6hq7CSbBlJFP5cIlVJc4MYyZRCKJdyCIOScDXZrtfF8LyLJM
e3s7Tz/9NIsXL+bGG29Er9cTDAbZuXMn69ev/1sZYgL4xQzu/NL3+cSiS9lc475eBqMqbvj0
t/mX9aWjx8VYkKA/gKNgOvl9A6OGGMQUEZ8fVU4J0woSaNN2PzrJUEsDLQE7S+9YxTSbCk9r
HcdbGrA7ljE9c6z4hhANh88y67brUWwA4yeVSjE8PExJSQmSJBEMBidUr3j80aApD0G/lizz
Ow0xYipKKBjG+hfH1QYrs5bfxqyew9TVvy1dus5E0YK1FAXO8cSh9nQLgr6EFKTLp2H69OkU
OYwIAjhLy8kPNhEYCCDKwxwZymJZRSaCGKardxBk8HQ0cLalnY5tQ2Q4cqleuJwSJTv0FfNW
hZjq6mr6+vrwer1kZY2UGhkcHGTLli2Ew2FmzJhBbW0tRqORtrY29u3bRzQapaamhsWLF0/M
ENPb2MSRf/8K+zLsFC+6mfs+shiTGGD4wkUOtz5CwzYbObNu4OP3rKbEpv9wh/nGI/jR4NDp
eWvIL2h16FUaQtEoYqCb+m4tyyoyQYwxONAHxkLyi4vJaY1SMGsWWUYL9jTMDD2ZBAKBUWfX
8PAwg4ODTJs2jbdC2/Lz8zEYDJw+fRqLxUJFRQV79+4lOzubjIwMbDYbgiCMXwYrUYoAABkm
SURBVAD23FV89VdziMkSCc9Z/vCrX/ELg4tv31LJ577/OzYlZVLhdl799ZP8cLODnz6whLFc
YR8KNBq0ajWqvxjCyW9GKV625xozedNs5Gb5mF5ZqRhiJkBnZydGoxG73U5hYeFopci3DDFL
lizBZrNht9tpbW3FYDCg1+tZt24dWq0WSZIm5ghDBKMzjyyDBlV+Luvmv8qTQx5kyYXOlkuB
UYeKPG6+fh/b66dAblGNnTypkc7hQTJzzFi1AokhD8OhMJZpDjQivFX+RUwlSSaTl1xiYoqU
DDIyoJRJulIkSWLfvn0cP36cZ599FlmWycjIYNGiRWRkZKBSqVCr1ciyTCKRQJIktFrtZdNa
jlsAoeZ9PN+qoijbjDrUzu5zJubckU+k9ySvHvaSWZCBLjnI0Tc8LFpSgpjw017fwEBPE339
PQj1JzkUDjF7cQmhlpN09XXR4e5Dda6Ow4SovIYLZFwWwUjxzFyaj5zneCSIy6rC19tNUF/E
rFwzgteGMdBJw7k4qWAvrZ0+yjIBtFjEQU6faaTUbiXHVYwjHZfAJgGv14tWq+WXv/wlDoeD
VCrFtm3b6OrqIiMjA7/fz4kTJ5Blmfr6elatWoXL5eL48ePs3LkTh8OB1Wpl1qxZ4zfECDot
4Y4znGlspdMjMH317Xx06TSMRgOJgSZO1zfR1hche+FG7l1bjTbp5sTO7ZzoiWK1mSA0RE+X
zLSFhfQeeJ6DTQG0GRY0MR+9XX5cc+dfswIYKxZIbXaSZ5dxd7TT0e9H4yxj3oIqnAYBTHZs
oU7OtfWT0NrJKy6hwJmF3WLBYk/Sce4C3phARm56VogZHh4enXxeLUKhEDabjbKyslFDjMVi
QZIkXC4XQ0NDtLa24vF4WLhwIbNnz8ZisWCz2WhsbBwVilIhZpwosUDvRqkQo6CQxigCUJjS
vKcfIJFIXM22XPMkk0lEUZzsZlxzpPN98p4lkjo7O8d6WUEBGFkYGBwcnOxmTBhlEqzwgVCy
QigopDGKABSmNIoAFKY04w6FSPj7ePFH/8RPDyWxven2uO4ffsrXV+rY/+R3eXhLBxnmEaNM
4R3f5cefrMbbVc+B155nyzG484ufZ+O8QjRinN6zO3jq91s41uFDNpex8QsPcX9tCeo0C4qR
kyHaz+zltddP0h2SyS6dy+p1N1KVZ0Ez5iNGJBqMo7MY066/1wKyLNPa2sqvf/1rli1bxs03
34xOp8Pr9bJ9+/a/YYWYZBi/kMWnH/shf7fYMXo84e9jIK7nI//yY76yoWz0eCrio73xFDFL
CXku/6ghRoxF6O12M/O+R/nivGz8u37G3//+NW6ufYD0yjEg4ms6xqFOHSvv/xcqs1T0nD3E
0WOHMa9eTbljrEvs5+irdVR9bA3ZV7W9Hw5SqRRer5eioiIAgsHghEIyxu8HSA4S8GopNr0z
ciuVihH0B7D8xXGNycGCjZ9lQc9hOjqOjh5XmxzMW/9JFmu1IMcJqgS0kkxy3F2YZKQAFwcE
KufMoSLHjCBA/qxqiqPnGO7zUSqEOet3UFNkQ5Bi9LuHQQZ/XxMtXc34d0OWNYuyyrnkpV15
nMkjHo/T29vLnDlz8Hg8DA8Pk5k5Ul5leHiYXbt2kUwmKSoqoqamBr1eT29vL6dOnSIej1NR
UUFVVdXEDDGDFzpp/sOPacu2kFdZy7rrq9GLAXxdPTS88GtCJ+xkTlvE+psWkmfWXTbM960K
43LST8uRHTy3a5g1d61Ps6c/kAjhVekp1RvRvNlPlcGAUasjFIqQ8pxn/4Xp1BTZIBWis60V
2eDCAfDmArSMshI9XoLBIH6/n9raWo4ePfoOQ0w0GiUQCCAIAvv27UOtVlNWVsbOnTtJJpNY
LBaCwSCSJI1fAOasBXz869/AJ0uk/Bd5/cXf4FZ9lQdXTuO2f/g210VlxFgfR155mp/GTXxv
Uw1jGWLEcD+HX3qGV+pF5ty0ibW1M9Gkm3lGpUItvLuujQxjl3vVZTKzOpv+C1C1Zg3Zyhxg
3HR1daHX68nKyqKgoICWlpZRQ0xOTg4333wzDoeDI0eO0NbWhlarRRRF7r33Xkwm08QLZOiM
uVTX5gIyUmoR+u4jPNnRh/rGQqYvWM50ZGQxSVHoPF+u7wZqLnseORni/P5nef5Ekhs/9WlW
zcxCrxnDQXUto7XhTAYZCAcokO3oBZDCIcLxCKpcG2la9+aaZ//+/bz66qts3ryZRCKBy+Wi
trYWs9mMVqtFr9ej0Wiw2+1cvHiRVCqFyWTCbDaPGmZgAnMA36kXeMmdz8IKJzp/Pa+fkSm+
NZvgxb28dlbNrDlFWFJdbH+jk/KqW5DFOF63m3Cfm1AoiHewj+4uAw5TkAP7DmKc/UVm2WK4
+3oAI9mFWRjS6YkoWJhZaee5/cdIJFPMylLR03iSrmguKxbbENxGVP4B+gZNRPvP09jUzbTF
VYAaXbCTho5+qq16zNZMTGlYIGMy8Pl8xGIxnnnmGTIzM0mlUjz11FO0t7dTXV09WkBblmVe
fvllVq1aRUFBAYcOHeLQoUMjhTEEgeLi4vELwFA4E9vxLfx2+yBxbEy/6bN8YnURhqQaZ3gr
z/x8K4GUgYL59/HVO2YTC17klV/+jCNvuiO9Lz5J3Ys1fPbRFVj02XiP/ZF/P/bW2Wv44o8+
x8y/3rW6CgjoChdyS63Anj2v8ccgZJfPZcWaxbj0AuTPY5X1z2x7tg6bq5Dsspm4LDrATtWK
Yra8/BxtznJWrN1IRdqVyJwcgsHgqP3xrbnk0qVL6evrQ6vVolKpeOKJJwBYs2YNNTU16HQ6
rr/+erZu3UooFGLlypUjFWaUWCCFD4ISC6SgkMYoAlCY0igCUJjSjDkHiMfjNDc3X+32XNMo
06V3k0gk0OnSd/lKmQSPAyUrxLtRskIoKKQxigAUpjSKABSmNOOvDxBys/t3D/Oz1/tHj133
Dz/j6+tcRIcusOMP/8O2/ReJ24q5/cFvsWl+BjFvN8df38qfTsDG++9lVaULVSJMyxt/5LfP
7KB1MImhcAmf/ZfPs2aaY+wgsmsWEe+Fw7y6/TBtAXDNWMSNa1dQYhuzPIzCX4Guri6effZZ
FixYwIoVK9BoNAQCAQ4ePMjKlSsxm83ve47xO8JiIfr8KT76zd+8wxAjhvrY88R/sTO5im/+
8l8poZvuiAUx7OXka5tpDFgQ1DEC8RQyIIkyaks5n3r0Y8zIEmja8v/x9f98gXk/+hTpFREg
EW49zKung8z+6N+zKVtFV91BTuw5gHDjSorNY/3Iejnw/JmRCjFpJ/jJJ5VKMTQ0hMFgIBwO
EwqFcDgcSJJEKBS64nrOE6gQM4BvWEuB0fiOJ3XI30R9u4Yb//EWZjp0QBnTHQB6lt/7NZb3
HObffn/JEKMxWpi++HqQJZIxP0ZLFhl2C2lXhloOcbFbZObcucx0WVEJUFRVg0dswtMXoDBf
pCdqpDDTiCAn8QfDAER9nQwODaA9fx6vwUxOXjF2wyT3JY1IJBL09fVRVVVFIBDA6/Vit4+U
2AmHw5w7dw6ArKwsioqK0Gq1eL1eOjo6SKVS5ObmUlBQMDFDzHCXG8/ePyE1G8ksmc3immkk
hjvod6txNO/iufooKks+C5Yves8KMTFfH2eP7qahbYCO7jgfuWM5VzfP8F+BRAivxkiR0Yz2
LUOM0YhJqycSDJEaaOaVtlIeWDMNkgFam5tAm4HK30n/8ADRcxoyHLnoMhUBjIdwOIzP52P+
/PmcOnWKoaEhioqKkGWZ4eFhjh8/PlobYMOGDRQWFrJ79246OjrQaDRUVlaSk5MzfgEYbRWs
vusu+mWJhP8iO/9wjO7kF9mgF0nJKiQxgShGaD+4laMegcf+bhm6MaP8R7Yg1EY7OU6Zwa5+
EgtyScMs4ePDkMP8eXmEfTZlCDRBent7UavVOJ1OcnJy6OnpobKyctQQc9NNN+FwODhw4AAt
LS0A+P1+Pv3pT2Oz2UY38MYfDm0tY/WmMkBGjPnY+4tvsPV8L7euziEvs5fq2ttZnivhfyPI
p//YhO/vlpEz1rkc+Sxedx8LklGG67fx8L/t4cLtc6n6ABfmqqOzkJGK4ouGSco2dAJI0SiR
ZBwhyzKBEjwKV8LRo0fZv38/x44dIxwOYzKZWLx4MUajEb1ej9FoRKfTkZeXx+DgIPF4HKvV
isPhQKVSodGMfDPjXgYN1L/Giye7CSZFpGAbjRejWCxmLBlzqSjz8cb+0wSSMbq7etDnZjNW
4cNoqJNje0/QH0iAWkvS58GNRNptqgsWygrVnD99hqb+IHIqQlfjGToGZJx5NlQqgVQ0SkoW
8Q100dbWS+yt93oH6I9KSFIKJefulROJRPB4PHz1q1/ly1/+Ml/72tcoKyujv39kZVIURURR
xOfzsXfvXlwuF06nE7fbTWdnJ7FYjKGhIVKp1PhDISK9p9n6xK95ta6HKJnM3vgJ/unu5TiN
aoI9Z9j2q//Ly40+rOXreehfNlFOC799+FF29Y/E0oxMnK/j2/97P4Fnf8kfdzYyEJYwFc7j
kw/9I+srMq7ZZdCxQiFkWcR38c1lUL+Ma+Zibli7ghKrGkH2cer5P7L9vBdHfgnO/AJmls9m
TpkDb+MrPPliHULOTG689S6q0rBg8GSEQrS1tXH69Gluu+02VCoVsixz9uxZuru7WbFiBU88
8QR1dXUAbNy4kZtvvhm9Xs+pU6d48skn8fv9rFu3jjvuuEOJBRoPSizQu1FigRQU0hhFAApT
GkUAClMaxRAzDpTp0rv50BpilC9b4Uqor69n9uzZk92MCTPmPs21uhSpcO2RzveKMgdQmNIo
AlCY0ow/HDri5eiffsIzhz2jx2o2fYfP1TqJ+7s4+NJzvH6im4QljzX3PsDNlTYSgQHqD+9k
VwOsvONmFpU5L31waohjf36OF/YNsOgLD3HbzIwxo0evXUT8HafYs+cknSGZ7LK5rFi5mEKL
Yoj5W9LX18dLL73E7NmzWbRoERqNhlAoxIkTJ1iyZAlGo/F9zzH+CjGxEO0d7ZSv+2c+WjMS
6WPMdCBHvZzY+ku2teVz52e/SJFqkIBehxj2cvTF33LcraOrH/oCsXdkww9cOMWh/na8rV4G
fPHxNueaINF9gpcOdlMwfy1LnSp6Gk9xePcRVqyrxTVmaKufo680Mn3DUjLTT/GTjiiKuN1u
3G43g4ODRCIRbDYbyWSSvr6+K96xH78AEr0MDenJLy6nuNg0etzf28Dh0z6u/9w3WF1tBt4q
k2Rkxce/yYreIzz+NkMMyIjRPo6faCMzfwGzik+k53hMDtJ0zk/p/MUsmFGITgCnTUuy7hxd
nX5yp2nxJ7XYjRoEJGLxkarqyegQ7sFBbG43kkaH2ebAqISOXjHxeJzu7m7mzp1LLBZjeHh4
tCZYIpFgcHAQv9+PyWTCbrejUqmIxWJ4vV4kScJisWCz2SZmiPEPhpCa6zgU0WLJLqa8JJv4
cDsDQzaKAk0cOZxAMGRSNrMMp1F7+SGNlMLd0kCrT2bu9VU0v36CtHz+JwN4tFZKzDZ0qpFC
GWqzBbPeRMQfINnZyP9emM4XbyqDxDBnTjUiayxEOk5zsqmDc/4OMrJLqL3pdirTMBhusohE
IgwNDbFq1Srq6urweDwUFhYiyzLd3d088cQTBAIBcnJyuOeee8jLy2PHjh0cOHAAURSpra3l
lltumUCBDJOLmXNraG87wP7mIAMBC9d//HMsTcQIR0O0NxyhK+DH0zeEfdXf8ZXbatBexhCT
jHioP3EcyfURqgr0pO2WmyQhyu8uciTwHnsppmLWfKwUlfxmkTxlCDRu+vr6EARhNNT57YYY
l8vFhg0byMzMZPv27Zw9e5ZUKkV3dzdf+cpXyMrKIh6PjxTRGO8HmzNquPsrNYBEKtzPKz/5
Dq+d7GLFymzysnNYdtsDLM8RGXj9p3zhxTo+f1sNl3uwBXuO8sorbxAslQleiNDU1kTq2V8w
Pe9hVpek0Q2hs5AhxQnEo6RkO1oBpFiMaCqBymFSDDF/I44dO8aRI0fo6+sbHdZcd9116PV6
TCYTVqsVg8HA9OnTOXXqFKFQiMzMTHJzc1GpVKO71+Medoda3mBvYz/hpIyc8OHxShiMOswZ
1ZQX+zl1ooWwKBIMBdFn2BlrHm52zeMTX/4m99+2itraeZQ4siiuWsi0sRw01yoqG2W5MufO
1tMyGEZORek930DnYIrMPMeoIUaUJQLuXrq6Bi4N9QKDDMYkJElUDDHjIBqN0t3dze23305t
bS3r16/Hbre/wxCTSqUIBAIcPnyY7OxsMjMzGR4epre3l3g8jtfrRRTFCTygNHDufx/jF+cG
iEsmCq67lQfXlKJ3aFh923r+8Nsf8NnfRzBkL+bzX16O5DnNfz/8KK93x/AGY2j37+AJ/XIe
2/p1FiwvefOkrVzcfJx49SJK7Gn09AdAjWPmYpbF9/LaE//BM2FwTqth1bobKLFpwDib2buf
5l8f3YLdlYcpw0U+AHamz0zy2x88wit5Vaz/6H3MGcs7qvAOenp6yM3N5aabbhqpNPrmULOl
pYWSkhJaWlp48MEHkWWZ1atXs2jRIiwWCxUVFTz88MOEw2E2bNjAPffcM35DzJj/LsB4q31e
2kKXuXRaIQ33Ad7e/ksIggCXmR+89do7r2U69ntyKsS8/bq9dQ9NNHZt3L8A7xn3MeEvMD2/
/Eu8R/svU0L10ktp3elJ43LXbaLXMi2X3hUU/looAlCY0ow5B0gkErS3t1/l5iikG6FQCIvF
MtnNmDBjzgE0Gg3FxcVXsy3XPMlkUskK8RdEo1Gys7MnuxkTZkwBqFQqDAYlWeXbUalUqNVK
hOdfotenbzJLZQ6gMKVRBKAwpRl/NGgsQMOezWw/6xs9VrHu89xe4yARGuDMgdc5em6AlMnJ
onUfpXaaEW9XPQf2HKTVHcOYV83aDauYnqknGezn1P7tHGn2Yiq5jo3rFpFn1qXfnoC/k+aw
jeIcBwYl+OeqMTQ0xKFDhygtLWXWrFmo1Wqi0ShNTU1UVlZe0dBs3L8AyUiAhpMHiGbNoba2
ltraWmbmGpDjAepffZJnD/WTPXsR82dmQVIgEfJyfOfz9OhKWLB4Dqbunfzsz6chGaLl4Iu8
cipE8ZyZyA3b+M2OVsa9nXwtEB6geyhMQonnuWpIksTAwACNjY10dHQQi42kHI7H47S2tpJI
JK7oPOM3xCTdeANGZty8guXzLy1/hQYbOXLsAjNvfZjbl+ehJUlK0qAWBBbc8gWW2rOwGFT0
Ro7x3OstuMOFnK0/hXPJ19i4poh45iAP/uIAnXdUUvIen6+gAJdMLxUVFaRSKXw+3xXVBPtL
JmCIGSI4LGENe+nqDqA32chwmIkOnadn0MX1OeDu7UbQGHE4M9CqTWTlmkBKEh44x57jXcyo
2YAh3oXXo6GsbBo6tYC2tJTC3pe5EIaS9F1WJuA7wWvPtiAzyEVPEH3ZGj5x62Kc5su5IhQm
SjQaZWBggOuuu476+nqGhoZwuVzIssyFCxf47ne/i8fjobq6mk9+8pM4nU7279/Pli1biEQi
rF27lrvuumv8AlBrzVhNeo5u/iHHBRnZXsmd93+CylAIj7ePfVt/zvaBYUJxIws2/T0PrJ4O
iRA9DW/w8vYDdGXewpdvq4bYqTfPOHJbCGYLDnWUcARIYwEgg8aYy/ybb+OjFj8HXmshlEri
RDvZLftQMTg4iCRJ5OXl0d3dTW9v72iWapfLxSc+8QmysrJ48cUXqauro7KykubmZr71rW+R
m5tLJBKZmCHGmr2MB/9rGSCR9Lez5T8fY+vBlTy8NIt8VzE3fOZr1Oak6Hjpv/jS84e4Z2Uh
/pOvsvnlMziWfJQv3VBDjllLeNCMVp8iFA4DZqTBATo1OdzoeL8WXOOoddjyp1GSZQJS2Mw6
1Mqj/6/OmTNnOH/+PC+++CKDg4MEAgEWLlyIVqvFbDZjt9sxGo3MmTOH06dP4/P5cDqdFBQU
fDBDTKTzNCfahoimRopdCGjQagRMmZWU5gdoOtdDTBLQqAUMZhOpYBcHd+5FPfsO7lm3gNw3
hwIGUy6FeVaaTp3GEwlw/vAJ/DOrmK48KBXeh3g8zoULFygtLUWWZTIzM0kmk7jdbmBkgixJ
EuFwmPr6eux2O3a7nWAwiMfjIZlMEgwGJ2aIERM+Tmx9jqf7A6SSMhrXUu6uLcbg0LFiw1K2
Pv8jvvVnGdS53H3fdWjCZzm1r5G21l/R9cabd7frRh7++s3MX7mO1j/+kUe/8TQqUwl337ds
zJJKCgpv0d/fT1ZWFvfddx96vR5JktizZw8XL14kPz+fzs5Ovv/97yPLMmVlZSxfvhy73Y7L
5eLHP/4xoiiyZMkSNmzYMH5DjJSMEfB5CcWSSKgxWB1k2kyoVSAl4wS9wwTjIiqdhawsO1o5
wlDf8KW6WABaG/kuOyoxQcg/TCCSQmWwkZVpRadSXbP7AGNWiEnFiIgaDDoNyHFiMRUmkxaQ
iEXiqA16NCrVh3ISPBkVYhKJBLFYDKvVOuoDiMViJJNJTCYTPp9vdFnUarVisVgQBIFYLIbP
50OSJMxmMzabjf8fz+cTRFnQsUIAAAAASUVORK5CYII=
iVBORw0KGgoAAAANSUhEUgAAAMAAAADACAYAAABS3GwHAAAACXBIWXMAABYlAAAWJQFJUiTw
AAAgAElEQVR4nO29Z3Rk53nn+aucUUiFQs650UB3g93NKFoSScuyqDhjjSXTQfLIH3Z3vLPh
eGZ9fA73zNnxeHdnR2N5xpaoZGXJpERbNEWJlMgmRXYGGjkUYqGqUIUKqJyr7n4opEYjVCE0
2Y37OwfnoMJ9771173vvfd7/8/xfiSAIAiIiJxTpu70BIiLvJmIHEDnRiB1A5EQjdgCRE43Y
AURONGIHEDnR3NYBhGyaX738Is997RsMjFp2XOAXr76WV8NDw8Mb/1unh7C6w4fYTJGjJp9j
PT40THrbe5de+Qlf+cpX+O4PX8Afjh9o3ctTA4ws+oA4w0PTB2rjqLitA/z6pRfQt53nc7//
GeQkAcimEgwPDRKMJgBwrbg2vr84M8mifWXjtWd5iZHxKUJ+Ly+//DNu3ryJzemlzFxLiV4N
gG/FwdDoJNk19cHlcmJbsDC76DjWHRW5nf2OdSy0yisv/4zrN29idbg3lpuxefnCF77ARz74
EN/+9vfuWA4gEQ0yMDCAx5+76LlcTgAiAS+hWJp4eJVgJMnc1DAvv/wLbt4cuqOj3S1u6wDV
DTW89cpLTMwvc7rnFJDh61/5MpF4kr9/7stEt2zlpZefZ3humcE3X+Kd0UUsA2/yk9euEPLY
sXtCt61kcfQK084w9qnr/OClS4S9dv7uG7kf72//y39kdMbOay9+B1vw3foZTh77HetYZu/l
i0pNKKXCHctF0/CNr32VdCbDjZsDALz22qvA5nnwXkK+9UVL36P8Dy09XHrjV7z6+pv8j//i
YUYW3GQVQwTdVsatvo3v3hgYwlBRB6RxXL1GkSrOHz/zDJK1z2vraunv7wdgfDb33q+vTfH5
P/o9VBJw2L5HEmg7fZ4PPfEb3JR4CEbTUHTbJokcE/sd6zmfQH1tLWf7+1FvWS64ssh//c9/
hT8h4TPP/BEp7/wd50hjbSXXrl6l8+zDe25Dc0c7dbVu+vv7jndn9+C2sy0UDKEvKuY3P/JJ
nF/7GoLWyOm+fv749z6OkE2RSEmYWPtueVUDn/mjz6OQSojH4/z8xR/hCsSoNGoQBAFpJkNK
AIVks/0Kg5wld4jWCj3+cAjxVH/3yOdYW4UM6Sy3PScUVTTw+c//IT/45tdJZTLId1iOqk/w
IY2Gb33lOeKPnCOz9rwbi8W2bYWETCZ1l/Z4Z2TPPvvss+svbJZhfvD8PzE4OEhjdz9tza3E
V2Z46Re/YvDWKK2n+gj6PLS0NFNdruPb3/0hg4ODyPQm3vdQPy987ztcv3ETU0MnTSYF3/ru
C8i0JZSoBKRFVZzt6+Dl57/HO5evce6xp6itKGXF5aK5pYWQ3422rJ5ijexd/DlODvkc61qT
mm9/6wdkVUXUVZkAcC4v09beSc+ZM7z96kuUN/chCyzettzrP/0+l965irG6md72Zhyzo7zx
9nVcbj+tPefQCVEy2jLMxSXMjv2aX1+d4FR/77tyQZSIyXAiJxlRBxA50YgdQOREI3YAkRPN
PdUBotHoXV1O5N3jbh3re6oDZDL7qDNHvJzIu8fdOtb3VAcQETlqxA4gcqIRO4DIieb2VIhQ
aLfvvSc4TGBkMBiOeGvubcRjvYbwrpEWIpG4EIlE8l4iGAze8d7S/LSwtOwWkrGQMDo5s9l6
IiKMjE8L2V2WExEEIeQQ/s//7zlBSHiFS+8Mb7wdWx4T/uG1G8K3vvOdAhvMCGPDt4SRoVuC
P5rcfDsZEOasnoJa2v2YZYU3rw8KgiAINwYHC1huZ+58BPLP85k/+TNSMScv/PPbBH0rWOaX
8M7e4C//5psEIskC+2SYn/7j6wgkGRudIhqNkoqHSWRi2Jd82O1LBba3SSYWRKIzYZkcYdS6
Sm2JhIFxKwCXr1ynvkLDzeGdiz1EgHQcoh6uTSzi9gV54YUXuPnL55lwJg7UXNxrRVneQs/p
HpbmZpiyWFgYGcO+6mZ6eppo4vCjcQG7BbcrQlIA59I8r778z1hmLLx1+SpOb6Dg9naMAR7u
b+f1d0aALN/9zvcYfOMlxmyFN75OU62JOVuucMa+ZCfonMe3PTHwAMg0RQQdMxSbaqmsK8JY
0UgiaANArpRTVFZLMuo5/IruY5rOPMri8NsApNNpotGDHxiZUk0qESObjiORqdbeFTAWl1BT
24hWdfhEx8mFZWqMUcambFTWNdHbYmbC6uXChQtUlhkLbm/HDmCs6STkmCQLQC5XrqyyGmk6
hUDhuXMqfRnpkJcskMlmjuz5M+6Z5eqEg2w6iXvOxTtvvU5FXTfT0xZUMgmX336D8qqWI1nX
fYm6mN62ei5ceJTWtjrqyvW4EhoqKyvpbqqi9/TpgppTGCrRCX4mZ5boaG9CJRUIpgWUymKU
Wd+R3AFqG1u5+OiTlOtAkU1iT2h5+n19DN+8xoovWHB7d2aDpmM4A0l00iSRrBKtJIErkKCt
qY55ywRlNS0UaZUFrCJDNJpGKUsTTkoQEiHiqSylFRVkEmkgg1arzaulUCh0oGD2oMvdzxx1
EJxKHW1efywWQ6PRHGi5mpqavL9/rOnQR/2jhMNh9Hr9gZYrKSk50m25LxBifPGv/itlLaf4
7cdO89wPf86f/emfMHjlDSyuOL/zsSf4x+9+E3Pvkzx4umHPpnKjNlkmx8cRBIGa5i6KNGuD
jKkQiyspGmpK8960SCSCTqfbaaO5PDDCQ+d6GRwe5mxv7x3LmUymvNeTdw2Cy+XEbK7M78vZ
JE5vhCKdav/vFkA6nT5Qp0qnxVrjnUivOpj3Ruh7vA6VrozKstzFpfVUP+OzLwJw7nQnw8FI
Xu0lfDaUZU00V6iZmJxhRSlHmUiiMKmZmfFQYTKiUR4uDgg6ZnG7o6QEcNkX+ZVzmYbWVlye
VVpa2tGrC2v/jhgg7Jrh//5/v8j3fvwy2XSCkdEJskKusDkRCTBhmQdgaX4aq9XKf/qrv8Th
XsW2MIPHHyaTjDEyeJlfXBpYazHL0MANFpYcxMIBbt7K2aWsOG1MWeaBLAtTwyy5Cr8lZ+Ih
btwc4OVXX2d0Yoar77zBnN0PwNCNK1y78haWxZW9GznBZFQV/F//4S8YvfFrtAYD0rXy1c3H
RTkGQ/6PIVKlmnQiRjadQCLfvPgZjMVU19Qd+uQHmLY6qSqKMWFxYK5poKepgsklL/0P9GMu
Kyq4vTvuACpdMUppGp3ByE9f+BGG0iJeWsmNDPzohz+gSCVjabGR+eUgj57tACC6Mssvrlgg
G6dcnaGmoZYsilyDqTDxtJxiiQSN3kixIfe8X1FZSyg8C0hpbKplxln4lV2mNtBcU04sBeWN
FfR0NXPt2nWaay6SzMKFBx/jyvVrVJefKrjtk4CEDD/9h+/Rd/FxLENXiUUi/OSVS2hiDiKR
GEPDw1y9chOA1f5uStR7t6fQV6D1zmGZW6W1rRXH4hyhtECl0ogyO00saTp0J6ipb6aquhq7
3c5qLIUjoePDj3QxMHCT+pYOtMrCkhvu6ADhYJgzFx7h2vUbNBVLGfWE6LvQQmgZgt4VQroS
uityJ6vaUIxerUDIppmdHqe1q5tMJoSQScNaB8hIdVy4cIaJ8TGg6lA7v510xM3Iop/HHzzH
8IwdjXEVtbEGn89HJp0h5HOg0pUf6TrvF3JBsIyPfPxTG+/9bnP32n/neGTtv+amptw/qRCh
Pa5R61mYFVW1AGTTKSpr6qgESKapa2wGMiST+Y0EpdNpksk7Naey8nKSySQmk2njWT+VhdNr
scCdhfd7c0cQLGTTTIyNUVrVSIVRxcjYJC0d3USCPox6DZMzVrp7TuGyzqAyViHEfGRVRjJh
NymZnpoyHYsONwZjKUU6FelElHmrHaVGT5lBxbzVTnFZBQohgdsXoLa+Hp/LQTQJHV1d7HWB
2B4YpeMhRiZmQK7mdFs9liUXXW3N+Hw+jHo1U/PLdHW0EC0wMDoxbAmCH+2p5pU3rtHac4Fy
RQiLK85H39fLt/7hJZzLXv6XP//36PeNGLOMj4yQFaCurRujZv0pIMi8M0VTXVnem7b7yJ3A
WzeGeOyBM9y8dYv+M2fyXG5njnUUKB4/mHXebuw+MrD/cmVl+f/4J4W0b5b/9S+/ycc/+Ske
feAUK9Yp3hyx8ZEPPsI//dOLfPazz0Amzje+82P+6A8+s297ce8CtmQ5rZUaRsenUSjlqOJJ
FGY1oyMrPPbohbzFsN1O5IB9ml/ecvORDz/Cqy/9BKVMSWN7O063j7b2TnRKaUEd4FidKNTq
fR4aCySVSh2ozaMejr1fWA+Cv/HcV6jXxrhujfDpj31oIxgGuPqrn3HhA7+VV3sypZpUKEY2
LVlTgjNsKsHaI1SCkxtKcK0mzVWrl998/CIqmaRgfeM2X6DjQWBidJhQLINSmmZuYZFkVgqp
KMsrfgxqGZbZOaxWO6aqyj3zs5PJJCrVzkOrSzY7lqkJImkZZcUGFqbHmJiaQqIqQa2Q7Lrc
SSabivHiC/9AW99DKLJRZiwWlv1x5ofexuOPIDeYkCpU9HY05dWeTKUnturAseKno6OVaMBL
MJbGXFtPyL2EpqgMhTy/IHW3Yy2RKejqOUM6FiQZ8RMQdDz+QCeDAwMoNEUoZIUd6+P3BUr5
ee3NMfovnEWnkqOQS7g1MkF7awsOm4O2jjYAhoeH6d0mamxnv+c768wYwayOnvZG3rnyDg8/
+BDvXLnK6VOnRCV4G6ISnOP4zbgUxTzxgYe5OTjI6Y5mbgzPc7qvD7Vi80oQcC1SVLG30rgf
k+PjSNRGelpzoxAIgJDmbuzivYjBYLgtCL7QbuLSlVs091ygTBZ815XgTCazy+Pu3kpwoTXB
x352JKJB5q0OVBo9i1YbBoMWr9eLJBXB4/VQFqhiNZympaXwTL6tyDQGgj4XDreOyKqb7tZG
Ll+5Se+58whJ0RViJ7YqwS0tNbx26SpZJCdKCT72DqDSFtHZuZNCZ6K6rhGAUmPh+T3baWuq
g6a6taZzeT8PmaoBCBVawnBC2BoEn+n6LJ//3DN8/fs/5alHzq59Y00JzvNpSapUkw6vBcHy
9SB4XQnWHKESnNpQgms0Ga4veXnisfOopBIikfw66zrH2gGO2o8nHo8jkxX+I8bjcTEG2IGt
SrBnaYZLV4d58kNP88pPvn9ilOBjDYLXO8DSwiwZmYZacwlW2zLVtfWoFFJCoQhFRQZSiSgp
QYFWrdizvTt1AIGZ0ZsUN55BnQ6w4PTR05kLqr0uG7OLy/Sc7UdIxkQhbBtHHQQftffSYYLg
qqr8Mw6OP0LMRomllLQ3VhONhGloqGd0bILqijLcqxG6i3S4bLPEFTW01ucfJOXaTmHUKvBE
0lQbDGST1o2PZhZsXHigj2uDI/R0tR7xTt375BUE//ZjfP2r3yIuL+JP/viz7H/tPjolWCaT
HUgJLvQJ4fhtUQQ5UkmC6wPDaDUqpsdHUetLMFVWo1JIASm1dfkPW92GVIlhLeV6e5GOVLom
xmTFAGA31oPg2to6WlpaSCUSG0FwKuwGqYrP/P7vIYmH85rD676pCT5KkokEWUFAKpXg9XiQ
a/SkkjGcdmvuOS4QYHZ2EbttkTzzpDbIJqOMWJZYskxiW17G4XBiX/ExMzNLudHAtSuXaWov
rKzvJLE1HTqUlvP5zz3DzPjwxpVXyCb55je/w7945hnykZbuxZrguxIDHBWHyQUSY4A7SUb8
vPDjF6np6KdKE+fS1WEe/82nmb3xS6zuEOfOnWVgYBCQ85nPfS6PZDiwzlsIxzO0d3Rgm7cQ
DCboPHuKhYkJaps7D50LZLfbqampYWnJxqrbQVqu52x3EzcGhmlo7UKjkLx3kuGOOjA6TEmk
0Xg4neF+Q1SCcxxrEHyQIcu9kEqle7Qp4PF4KS/P5f9nU3HGpxc5daoDqVR0gNzO9iD4/afM
/OiXN+m/8DBFwqqoBB8ZQoq3Ll2mpqmFMoMCp9tHIi3BXKLB5grS39fGxOQc/tUgDzxykb0H
QnfH5VhmbG6BDzya6wCXr1ylt7eLawPjdLfVHd3+3EdsVYLnZ0fISJVUV1dRWdx8YpTg4780
ppPoS0qJRMIYi0tIxSLIVRrM1fUUaVUgVVFfY0Ku1R6qN5qrqynRb94ypQoFBmMF6UThXjEn
ha1B8OlHP8Kffv5f8urPXj5RNcHH3gESqSwtra2kE1GCoShdvWdIhDcn3CYTY3zWyfmzp5Hs
3sy+OBwOpqamsDrcWKan0StkXH7nLUorxKv/bmxVgqN+F9/57vN86CO3K8E/evUm9rFfs5pH
bZNCX4FWCGKZs9Pa0oBSCqG0gFJpRJn1Eyt0mG8HauqbOf/Q+ynTCSiEFI6Ehg8/0svowE3c
q4XHNXdhmlQBh3URTXEFOkWWRdsyNfVN+FdshKIJTCYTbrcbkNPa0bKn2CIaYx0dohKcQzTG
OsnsFwS/i0rw3aoJPtYg+Kg7gGiMdbTsGwSvKcHf+Pr3SMO+HWBdCV6vCXZuqQmenl7BXJF/
TfBu3KEEO+x31AQXwl0YH9w0xgq6bIxOzeD2BY7EGItskuu//EcmXXGWl5f55aW3Nj4SjbH2
Z78g+CQowcffAdaMsSQSCaFYAoU0i0QipaKyFrkky7oxViJxgLuFVMnpnpw5V1VVFaaSzcej
dWMs78rC0ezHfch+QfDNW2NI5TJ+8sMfEM7jJnp/uEMfIdFolEwmg1QmY2J8jI6OTmQyGePj
Y3R3n2J2ZpaW1hZI+phxsm826E6pEHHXJAs00mlWMzw8SG/vWXw+H9OTE5zqbGLGGae9wSym
QmxDVIJzHLsQJqQTzMzZ0RWVEg74WPGuUlFVj9NuJRqLshoI4HO5iCUhmSnd0xhrO9lklAlH
DLBgy5aTyYB9xYdGDucfOMvU/DJnunPGWCK3s10J/vhvnOHbP/onzj78QdQJZy4I/s0LfPnv
n0dQGPjC5353z8cFUQneAalUilKjp6OjY+O9knJz7p8yI9VrQ/RleY7QSKXS29IapGo9/f39
G6/rt/X8nq62jeVE7mRrEPzLn7+CQqNFq9XQ3LpWE6wupaWqmDFHfnaD96ISLBpjnWC21gS3
VpXw1Ic+wisvPE/fn3wegGQ0xINPfhzrV/+WcAaK9jm3xJrgHckZY6kM5VQXq5hxeDGZzGjl
GbzBBI11ZmYtM6QkCjrbmg+8FofDimNpgYy6iot9bSxMj7Hs8VHX2odRcxiN+f5laxD88OkG
fvT8j3n0iQ9tKsGTM0wOD1J56sK+Jz+INcE7s8UYy7doIabU0d7cTCoRyxljtTWRzEqZHh6i
/dxZ9pp8aT+RY+jaOzSfeRCDUioaY+2DqATnuKvGWP3nzpHNpBgaGeHsmb7c51I5c2ODlNQ2
7Hny70s2STApw7B+BRCNsfYkryD4Yx/CNTfE9381yf/8x5/Oo9V7ryb4rhpjeVcceFaDFJdW
4FhayBljubWsBNNIlKtkKkrzkNt3Jux1030uFxBbpqdFY6w82DcIFtL88vIEZar8ru73ohJ8
142xyiqqN/5fN8Z6n+mARfFb0JtqWJfB2trbAdEYaz/2C4JdsyMsOpaxL8zywY98iup9jIHu
RXdo0RjrBLNfEOzMlvHv//d/y/DQ8L4nP6wpwR4LkzNeOtZrgtMC1cpilNkJoomKQ3eC2sbW
zZrgaBJ7Qs/T72vixs1rGzXBhXBXjbEa66px2q1oiyswaJVrxlh6nPYlpJoiKkqL92xvr6J4
1/IydoedupZuTMVa/G4H0/N2uvrOIk0nRCV4G6ISnOOuGmM5FmdQl9agkkvwuJw5Yyx9I7ri
ChZmpigrLT5wDFBqrsRoUDE0PYfpXA+Tc1YevNDPlevDnD7VsX8DJ4y9guCIbZjJBRdPf/r3
ePMfv09KX8XnfvcTe7YnKsG7scUYSyNNo0kJ2BJZek91EAzPglRBLOgkHE8fqiLMZ19gZtnP
Q+dzxq5SqRQkciR5WTqdTHYLgh/40CeQvPR9FkauUtz5OGrnAM4YVO5zQb4XleC7aoxlrign
kckik8k2jLE8Hjf+UBy1LJfBeVDswSxaBbi8fmZnZqgsLeLa1cvUb8x8KLKdrenQKrWWpz76
Sa688Ro/f/EHlHU9zvlTDQR8XlbDcTR5uBXcizXBojHWCWarMdZ6ENz38JPM3HgNVyDBo098
hJXpq2QMDXzwkXN7trV+rG2Lc0TiGVrWleBQgrbeTpamp6lubMu7E+x2rJcdjk0l2OMkLdPR
19nIwK3RDSW4kGMtGmOdUEQlOMd9Y4wVXPUyv+TkVE83cqlENMbah+1BcG99EVeHJpDqKuhv
KS04HTrHvacE3wV36BRvvfEmc4t2fC4bI2MTrHgDuBxWbg6OAuBfsfHqpXcOtxqlnq5mM1eu
jwA5Y6yG2hKuDYwfehfuV7a6Q/ddfJwnznfQeurspjv0Wjp0YocZ23dCdIfeiS3GWEu2ZdQK
KX6/f9MYS8hg94SpKj+cUKXMRrn01hWqanPqr2iMtT9bg2ABgTdvLfD4maaNK+96OrQh5Sec
x7kr1gTvwFZjrCK9lvKaeqLhzZ4aC/pIZQXsNvuhrhDeYJBSkxm/zysaY+XJViU4E1ul/6EP
IIHb0qF/8sPv5J8OLdYE78SmMVZJkYalxXnKK+tZXTfGqqyh1KgnEgmj0+0d4IrGWEeHqATn
EI2xTjJCmu9/8+vIypp44kIbz/3w5/zZn/4Jg1feeNfdoXcf8t5bCS50yFs0xjrBuC03GXeE
uVCrQaUro7Isd3ER5wk+UrIMDQxgNFVTVaJh1uamwlxJIuQlEo1SWtmI2zaHoNDQ3XHwyexW
lpe5NWnhqfe/D4DRwWtEk2mKTA3UmfdOsjupKNVqes49zOrsEJInH0W6lotyhzv0fTxP8F01
xpqZW0All5BKpampb0KrkhLz2ZGV1KPOpsnDgHhXKqqqMG8ZBYims1y4+DB+j/3w+3CfYqzv
xSxZpqKzD9vQVWKRCD955ZLoDn1UbDfGkiGhpaub6YlxVDIBg6mOcnWS6RUBWcxDY1fXnhNk
7JcKMTQ8RF9vHz6fD8vUJN3dbUwv+uhsqRVTIbYhKsE57qoxVp25GMv0FOXmaoJuB0HfCuqq
WrSCDcFQfODZYQCWl5fJZrLYlj1oVVLOnz/HpGWJc70dojHWDuSU4H2C4ILdoWF+fo6mpoO7
e6xzX9QE72SM1dXVBUClaXNEoNjQnnd7u6U11NTU3DH81bNWByCmQuzMvkFwge7QAJFohMGb
V9EoZOiquqgzFZ68uBf3VE2waIz13ma/IHjTHfoP8nKHXkdXVEJ7QxnTjjgccQc46ppg2bPP
PvvskW7hHeSMsUKxDEIqitVmx+sPoZJmWV7xU2xQMzVlwesPUV6691h9MplEpdr5ULgcDgbG
Jmmozd0FFqbHmJiaQqIqQa2Q7LrcSUZtNOOZvYGqshVZwM7M/BJWd5jFkct4/BGQyHC6XEyO
jdPRd5Z8L646nR6tVgNSBVr1wR5sdzvWEpmCrp4zpGNBkhE/AUHH4w90MjgwgEJThEJW2LG+
q8ZYJQYtiZCbBU+a2oqinDFWeysCAoMDg/T19x9qiqTBW4OcPZOrCBONsfZGVIJz3HVjrOn5
ZU719m6Ov0okrDiWkCAlnQXZUT2ui8ZYe7I9CD7fVsorb1yjtecC5YrQu64E3zc1wVuNsYRM
Aq2hBClsGGMVu434glFkCiWyQxQFOxwOAoEAVoebRHhVNMbKg61BcG1rLx9VqnhzxMaDH3xE
VIKPiu3GWC1NuezM6rrGDWMsk6ni0Ouprq6munrddCs35i8aY+3N1iB4qkLGqDXCpz/2oY1g
+CQowaIx1gnGWN+LefxF4p19kEwRXJ7jn3/5NoqQdUMJvnrlJgCr/d3s540lukNvY70DuGzz
rCZkdLbU43I5MZsrEYQMKys+zGYTiYifqKChRL939L5dCRaySW4NDKMvM1OskjBvd9J3th+V
XILXZWN2cZmes/0IyZioBG9DVIJzHPsjUDrkYGwpzMXeZgJeJ5feeZvf+cSnmLdMMb+4ivnJ
UqZHrxJS9fDwmcI8QpcnhqnoPMviyFUkrac4f6aI68MTXDjXzcyCjQsP9HFtcISeroMn2d2v
5BUEv4vzBN83NcGexQk8wRAvvvQL9GWVNFTnrsTN7d3oVXJAxunengOZYlV19LA8MYjL60ej
kSGRayCdm85HKl0zaM2KAcBurAfBGs1aEPzUY3i87s2a4DUlWBIP52Uvdi/WBB/7HaCirR/Z
9FugVOBdXmRoaBilvhJNJsTQ8BA1bfVYx64ybIW+U59EW4BuIkFAKpPS2tJO3LnC1RUHLb0X
mJmZpdxo4NqVyzR19rMejInczn5BcKFK8L3oDi0aY51oBN545UXi6ipqdSneGZygqvkUipAV
qzvEuXNnGRgYBOR85nOfQ5/H5dI6byEcz9C+7g4dTNB59hQLExPUNnfm3Ql2Ez3tdvumO7Tb
QVqu52x3EzcGhjfcoQsZ8BCNsU4oohKc4543xvI4bQSTUuoqiphedHGqowWATDLKxKydU11t
YjboDmwPgvsaDFy6covmnguUyYInRgk+9jNDyMS5eXOQeasdv9fF5NQkQ6MTW4yxssyOXWNy
wVtw2+nICtOOCFXlxYxaV6ktkTAwbgXg8pXr1FdouDlsOeI9un/YGgS3tLSQSiTIItkMgskp
wd4CleCu7m7sC7PMzM5iHZ9g2e9hZmb2SCrC7lCCf/FzZudmeefaDVzewm1Rjr0DBBxzJOU6
Vv1+jGVmtAoJhqLiTWMspLS0tRxoQ1Zts6yGI7z6+ltU1BVhrGgkEbQBIFfKKSqrJRn1HOn+
3E/oSisoLy1h/OYVxuaWONPXzeTEBC7bAks2G06XlzmrlXnLJLE8hoHkWiOR1RWCPhcqfTHZ
bJZwOIyhpIxKcyUqxeFPtzl3hA8/3sH4+CymqjpqTUX4AmGa2zop0hU+zeKxj3cgYdkAABmU
SURBVALpS03oY3GIRrHOTaEoqqK+vHAb650oazqFfOE6UoUC95yLRd8NzM39TE9bUMkkXH77
DcprRXv03dCWN/HppyWk5XqK1RIsGSl//PvvxzE7wZNPPAWAvqqDh/LUlWRqI42VGQKxNM11
FXhXBNJFJWjkRZQXBUims6gVh3ssbmlqRq420FQrw+/NINHU0F5VzpxlEl1NC9ICR/zugjEW
rLqdpOValEICp9uH3liKJBXJGWOZzXhdLrJAY2sHew0SiMZYR8dRB8FHTTQaRavV7vmdUDiM
YdugSDQaxWw2570e0RjrBJNNBPnrL32Z6vYzG0GwwdxErS7JrQUf/9MffpyvPPc93P44/9v/
8W/31wKyCa7fGEajllFa3UaxVoY0KxCNOrk+ssJjj+Y/TequFy0hyY9++ja/89H3c+mN16hp
6qK1oZqZqXFMtS1Is6mCLnaiMdYJxmkZwp9WofJ6aPrAGV5+5TWqOx/kscfPYP3ut0Fh5Onf
epwXfzmY14kScVspbz5NU7ma0bFRQkoVqniS8o7KIxPC7JZJqkxaAkkBQaZC8M3za+cyzW0d
KKWQLnCWobtijDU9MYnKUEKxVs6K149MqUGvgtVQio6WGqYtC8STaXpOdx84Kl9etmG1jJLQ
t/K+c62iMVYelFTVYSpbIOlbYXRuiUff/wTXR0aYqZCxZLPhsM3yN197nk98/GkyeRQraYrN
rFqWKEWLWl9OKuYnFApSLq1FyITJZnNTZR0Gm9uHVqVmamwKrVZLJhNDLpceeH65Yx8Fiqws
4I1LSaVSGEtNVFeUEk8kqaisRS7JglRJW1sLmUScQ0wRRlVVLRKFkYfP5hLfRGOs/dGUNfKp
33qMT332s7TXNyBXqPnDZ34XgCefeApBouJTn/ht8j1npaoi2mpKCCTltDZUYioporypFY3c
SHkRJAq9PO9A1+lz9D/wIB3NVZiLdWir23mw/ywRt5WUUPjpfOx3AJlcjrnSRHJ1Ca/bwUog
RXf7Ft8YIcPQ4CBdfWcPtTHp2CqCuhi5BHw+H0I6SyjgRqEWFeCdWA+CdcZchqYAtLa2kEnE
MNc2sh5GFhXlfr9EJERij/bi8U3rOI1CitvtBqkCuRR8bjdylZZwwEc4z+2Lx+O3tbkVtzun
UWRlavQKCW63B2NpBYlIoODaj2O/A6hL65HHXaj0RlLJFApSOFwenHYr0ViUVZ8XiUqHbdF6
qJS1VFrK2b6ujdfnz59jyeHnXK84R/BOGAwGdEqBr3357/jZ61cwGPQ8/9z/w8+vTXPryht8
8wc/xmBQ8OOv/Q1vDi9hMBj2/NPpdOg0CqYmp7AuzBCKCznlHkhGV7hyYxypQp37Xh5/avUu
39Uq+fmlAXQ6HZapMVzeADqdFpfdSgZ5wbY5x26MBdDYsrPxVfXa3BVlpsq829strUFn3Bzl
KS8vB0RjrP3YGgSPXXudrovvxxaHx558OhcEo+ZjH3uKtx35tRf12ChrPEVDmYqJyQnCCiXK
RJLSVjPVNdojKYl0zE5TWaYhmFoLglcXubziorGlDYVMIFvgVVQ0xjrBbA2CnSEDU0NDOKni
TLVyTQl2MTU2xbxHTexiN5p9zha1sRz/rJ0S1Kh0ZaTjAcLhMKXSGrLpSG6+aMnhgmC7x4dG
pcYyblkLgqPIZQcPgu+CEJZlYnQMdVEppXoFTrcPuUqPXpnFG0rR3dHE7MQQipIW6iv3Voj3
ErRcDgc3x6f48BPvB2DoxmWiyTTGiibqzEZRCNsFp22BtFxPbWU52WQEbyRLwLlAIJqkprYW
uy2XWtLd179nB1hPfQ/5fQRiaWqrKvCuOEkLcsrN5XgcSxhN1XkrwbulvoeCIQxFBoKBIH6v
E4mmhLo1JdhU04JUSL13JsgACDtn8cRlmDUpjMUVOJZXyCiymKvrCU5ZACktLfVMOw53lTZX
V1O14tp4HU0LPPTwY7x9+Qp1ZjEQ3s72IHj9tVoO6i1BcHt77vE1HQvlZQ6hNRjRGnJZmcVl
aydiJkO5uXrt3/yeUbLZ7I7f1eq0ZDIZdHodWcwY9HoymSwNzbntjEb3CtXv5PhHgRQKKqvM
pHyLpCVy2tpaGZk43gxNr9eLkM4QCqyg0Ign/04YDIbblODTZUl+cnWRRx55BGnQmlOC//Wn
+fsv/hfKz3+M334kj5yqI1SC17fxDrYowQM3r96hBO+XPrGdY48ONWWNKOJOVIYSAivLzC4s
UllVg2NpgUgsgs/vxzLnJBpwcpiSUYfDQTaTxerIDZE9ePE8i7ZVzp/p2mfJk8t6EOz1eogL
MvRqCemMwGNPPk2pVsp6EJwv60pwT+85fK5Flux2nPMLKIuLj2ya1B2V4Ks30Zrq8/Yu3cqx
3gHWb2F1jS0b7xWXr99cjZjXhoGMhs71JdjrDrnbbRHAbDbflgQlAF2drWQzGbLZwwsw9yNb
g2BFSTcXzxUxPD1FQ4nsQEHwvagEizXBJ5z1INhcrGF8coaOUz3YZsYLDoLXCa16WI1lqK82
43E5SGUVVFSZWLEtUlxRm/dQ6G4DHsFgkKKiIgKBAH7PMhJNKfXVJmamxqmoa0OSSbx3aoLX
O4BtcY6MTEOJTsGKZxVDiQmdIosvlKS+xsT87BwpqYL25sY929urA9gdy7gcS5RWNdJYU4F1
ZhKn10dN82mKtVKxA2zjqNOhd1NtD9PefkPe4UgE/bbzIR6PU1eX/+Toxz9TfMCB059Cq9Vi
KC6jvq4at3sFqUJNKh4BQaC2sYVMOMhhHHzKDBpS6TSZTO5xZ9kX4MLFh7DNTxzNjtxnbFeC
bcNv8qXnvs3A+NymEqzO8v1vf4e//tJXUd6nSvCxd4BkNEKRqRKXbZGMkMZqdaBUKTejdamc
+elRiqvqKbygbRO1wUhPZzsej3vzTSENEtEefTf2DYLX0qFLKyryChbXleCuU32supewOxys
LFpRGI1U19QfnxJ84xYaUx0KWeEPM8feAQyVTWR8S0iUGgIeD4JUgkKuwGm34vP5WPUs4wml
iQRWD5ULZHfYmJ5bpLm5mdmZGTqb67l2/RanevuObF/uN3JBcMlaEFzFxXN9zM1MMTMxspEO
/aWvPc8DZ7rJ5DGOoDaW43fZCXodqHRlGzXBSOVk00myR/C0bff40CiFLUqw8N5VgsUg+L3P
XkFwZaUZp9MFSDl9du8pku5VJfiu1AQfFWJN8NEh1gTnuCtpkgGfG4crZ08SCwcIRRMIQpZA
IOfjkopHiMQPlwoRDfoYHN0MeP0rdi5fvkIoLpZD7oTBYEAScfLf/u6r/Pevfx+/a4G/+Msv
YjAYDpQObTAYMOiUTE5MsjhvIZTIGaMpJFJSsRXeuTaKTKnNrx2DITdostNnehU/e/0GBoMh
FwT7ghgMelwOK1mp4r2nBGdiqyx5YpQVGwCB+ZkRFpd8rCw7sC45gCzLSxZszsJNjbaSlmoR
0ptDcWMzCzz0YD8jg4OH24H7GJW+iEQkhIBAXetp+k/lCpVOkhJ87B0g6HYQisW5MTCEbcFC
VUOuZNFcXbv2PCilvqHuwEHMOkV69W1tSGXS3AiQRHSG3g23dZaq9jMokjGWnTZsSzYmZhY2
gmCny8XQ2FTexliaYjOrziUCHjtqfTnZTIZQKAhSOUImSTZ7+Kdtm9uHViFsUYI5lBJ87GOE
xVWNyJyTSGQyFGodKw4bK34lDm2CJdsSZWYTXvs8S15oqCvb0xdoLxwOB3a7nbKKWhLhVapL
jVx+520a28RRoN2o7n6YpxQTKJ94DGU2wlNPPrHx2UGMsXI1wUlWYxlaG8x4XFlSxrK1mmA/
iXT20EOhXafPbVOC6+hcU4J1dW0FdwQxCD6hiEpwjmO9Axz1j5JMJg/UZjIpzhKzHYPBQNhp
4W++/RISpY7P/PZD/Oevv8gX/+Nf8NarP11Lh/4DRt75Bd99fZL/9Of/Zs/2ZDIZZJMMDI6i
UcsoqWzBqJUhyWaJRVcYGPfw8EPnCroD7DjkLaT48c+u8MkPP8bgwDWqGzporq9ibnqS8prm
95YSnM1m7+JfBrfbvfE6nYwyOjZFZu21yJ3sFwSn434mXGlO1+c3t5eoBO+AkIlz69Ywi7Zl
3PPTDE/N4PYFWHHaGBqeALIsTA5gsfoOtZ6VZRejUzMbr69du0FddTE3hiYPuQf3L/sFwVOT
M/jdNi5fuYxjdf87772oBB97EBx0LpKSawkE/OjKjWjSYaLRKA21tYTCs4CUxuZGZpyHW09F
VSXL7s2SSKlCjsFoIpOYP1zD9zH7BcFlda184cwDuJwuzPtNEkwuCG6uTm9xh84euTt0Z/eZ
bUrw4dyhj70D6ErK0cXiEIshUahpajIxPjkNtfnP5ZoPy8vLWCwWykw1JCJ+dAoZ166+Q0lF
45Gu535hPQguq6xde8dIe/t6+WjZRk1wKBRCq9PmHTTfazXBdyUXyO9dydUD6FUsLtmpqWvA
57IRjiUpM5nwud0IQH1TK3s9Joq5QEfL1iD4k+/v5bW3BykyN1JvSL/rNcH3hTu0QpGb89RU
uTlp2brLgG5LmWTFmpHVfsjl8o02C0EuF1Oid2I9CFYptbT1XsS2ZCdTbOaxR84dyBhLdIfe
xkFO1r0QO8DRsh4Eh+xzvPmzf2AmqOR9XeW3KcH3e03wXbFH3zDGUmRY8MeoNJkhGcwZY7XV
MjE5RzyZpvfMaQ56jdjPGEvkTrYGwdJkAJ1rc6LCk6IE31VjrGA6hUIiIJFKqVg3xpKq6Oxs
48b1QQ4TjIjGWIVxRxCsKaPduD7eX1KwMda96g59V42xzN3d1MlkjIwMU1G6Nr+rkOHm9Zv0
nH3gyDZGNMban+1K8I5BcAFTJIlK8C5sNcaK+j1MTU1irmncNMbyuJGqdVjnFw5VEikaYxXO
ViW4rfcinfUVmM3mE1UTfNeNsQzFayM+Rt2GMVZf6eZ48V6dQDTGOlr2C4ILnSJJdIfehlgT
/N5nwTKB0liJNBnA7vKiLzEhSwTEmuCjIBqNgpBh1jKLXGugrrKM6dlFOjvaCAd8OWOs2kpc
9nlk+krKjZo929urA8wtWHE7Fmk8dR6zUS0aY+2DWBOc49iD4GTQRVpdRszvIFlmRLZ2AcgZ
Y60CWQw6FY5AbN8OsBdZrYr+8/1cvjaM+ZELLPsCXLz4EFevXaf41Kmj2Zn7iO1B8Md/o/fO
eYJFd+jDk87KSEa8pLNSlBrtxjPg5oZK0WoPP5NMjUbJxPgEav2WSTZEY6w92RoEt7S0EPF7
MJSYxZrgo0SuVCIRBGRyGdGAD5/Px5LDtWmMFQgwO2/H57aTPMQwkD8cJ5mRc7a3UzTGypOt
6dDr8wRbZ0ZOVE2wGASfcNaD4CJlFsv8Eh2nenDMToju0O9FxJrgo0OsCc5xVx6QXQ4rCl0p
pUY9fr+f4uJiBCFLMBjGaCwCBNxuLyZTflmhO+F02LHZbdS39lBRosO/Ymdidomesw8c3Y7c
R+QVBD/zNF/+++dx++P8uz/7N3ueLKISvAuJ1SW8KS3WOQvRkJ/xqdz8YJvGWGCftzC9sHSo
9ZRVVtPT2crs7CwgGmPlw75BsLqUlkojyOV5JSnei0rwsXcAmaaIwPI88QxoDcWYSnOjNOvG
WJlkmGBaiVF7uJuRxzbHtdF5LvbncoxEY6z92S8Inp0aR1negCEdIZTHz3gv1gTLnn322WcP
vVV7EF11sxoXSCcTFOlVTE5ZkCq1RAMe5uYX0RmMJOMRlqxWquuaUMh375PJZBKVaueUrCmr
DyUJJAoNTvsSxVolE1PTNLaeRiVn1+VOMgZTHWXqLGcuPkpVqRF/MMoTT3yQ0KqHmrpGyipr
kaRinH34fZiK9h5fT6VSSOQqdAqBYAIaaiogk0JtLMNYVALJIAqNHvl++RRb2lMq75wxoqio
lIbGJvQaBbJsAkVJDV1tTazY5tAYypCQLWigRAyCTyiiEpxDNMY6oeSnBOdvjAWISvB27qYx
ViadZHR4mEg8JRpj5cl+QXChxliiErwDqbCHm0Pj3BgcJuBzY7FYGJ2YPnJjrJGJRZraO5Bk
c9GaaIy1P/sFwYUaY92LSvDxV4SpNKTiUeRKJcZSE6GgH4WmiIrKyiM1xsqqlUwMD4K6mHM9
7aIxVh5srQleV4L/8JnfxTE7cWBjrHutJvjYUyECdgs+RRWh5RlKjTrkBjOVZbmh0NmZWVpa
WyDpY8YJrfWle7a3VyrE+PgU0WgIpa4YnQLi4VUiiRTGikZqK4xiKsQ2RCU4x7HfAYw1bcQd
SxQ1tKAQEqx4V3Ckk0jTUQQEVgMBfO7c408yU7qnMdZedHd37PpZJBI5WKP3MfkFwb/Hf/jz
f4e58wJfeOZf7tnevaoE3xVfoNqG5o33yiru9NgQjbHeHbYaY7W0tPDyK69R3fkgjz1+JmeM
lQ6h1JSRTaXJwL5q8LoS3FCmYmJygrBCiTKRpLTVTHWN9viU4BUXjS1tKGQC2QJ1T9EY6wSz
tSZ4PQi+PjLCTIWMJZsNu93LA489xui16yQE0O7zgC3WBO9AJhlmdHIBmUJJbYURp2cVuVKL
QUXBxlh7CVr7GWOJQtjO7JkO3dhC1OtAVVxJTcXe8dm9WhN87JfGbCpBIpVFkolRXNaOXCZl
fjlAa1OraIz1LrLdGEsAWltbyCRimGsbN4yxdFV1t31/P+41d+hj7wDRwCqm2iaCy7N4XTaW
AylOd7VufkE0xnpXyCsI/vy/4m//+ktoq9v5g9/56P6NikrwnRSZ64j7bOiMpSSSKRRCErvT
LRpjvQfYTwmOOi0s+tOEvF6SeYjp96ISfBeMseQb/pIAm2lKpaIx1rvMfkFwQHiEalMZiqSP
QAJM+5h23Ivu0GJN8Aln7yC4FXkqRDgtp7G2Mq/2xJrgLWw3xirRKVjxrGIoMaFTZA9tjJWK
eLk+PIdCraG6RI/L56OlowejTsn89Dhu3yr1HWcxKAWxA2xDVIJzHHsMsG6MFfJ7MBSXUV9X
jdu9smaMFWHdGMsfiBXcts9mw9TSSTTowZPJImTSpNced9z+IBcefIhFy9gR79H9gcFgQBJx
8t/+7qv8969/H9vwm3zpuW8zMD7HrStv8M0f/BiDQcGPv/Y3vDm8hMFg2PNPp9Oh0yiYmpzC
ujBDKC4glUqRAcnoCldujCNVqHPfy+NPrd7lu1olP780gE6nwzI1hssbQKfT4rJbySB/79UE
bzXGEoQ0VqsDpUp5JMZY5o5e5AE7kWQWlbaE/vP9TI8PAyAIEoRMAqRiJdhubA2CE4IMvVpC
OiMc2BhLrAnega3GWKseD4JUgkKuOBpjrHSc1VCUnu4eKuUxblwfpKvnDDMzs7Q11nL95ii9
faePZb/uB7amQytLqrh4ro+5makDG2PdizXBYhB8wlkPgk1FSsYnZ+g41YNtZrxgY6x7VQkW
a4JPKGJNcI67aoxVpJGxsGinpqERtUK6ZoxlwLG0iExjxFxeUlC7QjrB4K0RpGo9JqMOq32Z
/vPnUcokeJ1LTC/Y6Tt34Zj26t5muxL80Qdq+MnVRR555BGkQWvBUyQBohK8E1uNsRLJNE3N
jUyMjW4aY2XTGErMLFvnC1aCBQFOn+tn1bOMqlTDhTMt3BycAGBqzsqD5/u4NTh09Dt1n7Bv
EFzgFEn3ohJ8V42xdFo1EyNDqA2lG8ZYSBVEAyuEYqmCAxmpQsH1N1+jtesMMW+Ukck5Mqmc
A4RUKkEiU4FQWHLUSWK/INhhm+VLX3ueB850k8lDTL8Xa4LvqjGWWiElmYVkMkU2EWZufhG9
QYfXH0JIJimtrkGxx55sN8aKexYYsUWQkaHIoMPt8tD7QD+Lc7MY1HImp6Zo7jqHUpoVjbF2
YKsxVl2ViVV/mA984DcI+tzU1DWiNxipr6tGIpFgrqpCts9ZJpGr0CsE/AkJTXWVSDJJ1MUm
io2lCIkACo0BRZ7GWLuZoBUVl9LU1IJeq0CeTaAsreVURwsu6wyaonIkQqagYy0GwSeU93oQ
fBjeM/MEi8ZY713EC0KOY+0AR52FuW6C5bQtEErJaGuqI+z3INeXkwp5cAXitDbmCjzS8QiW
JRddbc1iNqjIrtxVY6zgqocZi4WxScsWYywIeBy8/vbVvNtU6Y1IVxexrUaYGHwbVwRi8SDa
pJspexCAazcGqC6WMjRpO5b9Erk/OP5RoDVjLIAio5FUPIJMqaGisha9VglChmVPhMrS/G/J
mViYSYefYq2a9uZ6AKLxDL5EgtXlXEGMQq7CaKonEbQf/U6J3DccewcIrTgwN3WilGYJhGO0
nzpNMrK68Xk8tEpKyOJYXiaWVzJQCrtjBXOxDqfbw8jEDBNjYyjUWoKrcdq7G5iZnUEhy3D1
nbcw1e7uFyQicldygVyOJeTaYgwqKUsOF9V19QTcDsKxJGUVVZQU6fLK8xFzgUSOmmPtAKlU
6kjbC4fD6LflfuS7XElJYWkWIicD0RhL5ERz7GfGVmOsOnMxTrcPuUqPXpnNGWN1tHDr5jV0
JWbamhsOvJ79jLFERHbi2IPgdWOsWDyGsbiEbDpNJpvFXF2PgiyQIhHPwCEt88zV1VSVF2+8
XjfGWnWLw6Aiu3PsHWDdGEspEchK5LS1tRIJBTY+FzJSzj/8ENlwgKNKWxONsUTy5a4aY62u
LDO7sEhlVc2mMVYggGVqEpneuH+++R6IxlgiB+FYR4Hy9YHMl8OMAhmN4p1A5E6ONQhOJI42
Fz+ZTB6oTTEZTmQ3/n8edjFbAQdluQAAAABJRU5ErkJggg==
================================================
FILE: test/assets/index.py
================================================
import os.path
TEST_DIR = os.path.dirname(__file__)
TABLEAU_82_TWB = os.path.join(TEST_DIR, 'TABLEAU_82_TWB.twb')
TABLEAU_93_TWB = os.path.join(TEST_DIR, 'TABLEAU_93_TWB.twb')
TABLEAU_93_TDS = os.path.join(TEST_DIR, 'TABLEAU_93_TDS.tds')
TABLEAU_10_TDS = os.path.join(TEST_DIR, 'TABLEAU_10_TDS.tds')
TABLEAU_10_TWB = os.path.join(TEST_DIR, 'TABLEAU_10_TWB.twb')
TABLEAU_CONNECTION_XML = os.path.join(TEST_DIR, 'CONNECTION.xml')
TABLEAU_10_TWBX = os.path.join(TEST_DIR, 'TABLEAU_10_TWBX.twbx')
TABLEAU_10_TDSX = os.path.join(TEST_DIR, 'TABLEAU_10_TDSX.tdsx')
EMPTY_WORKBOOK = os.path.join(TEST_DIR, 'empty_workbook.twb')
MULTI_CONNECTION_10 = os.path.join(TEST_DIR, 'multiple_connections.twb')
BAD_ZIP_FILE = os.path.join(TEST_DIR, 'BadZip.zip')
TWBX_WITH_CACHE_FILES = os.path.join(TEST_DIR, 'Cache.twbx')
COMPLEX_TWB = os.path.join(TEST_DIR, 'filtering.twb')
================================================
FILE: test/assets/multiple_connections.twb
================================================
================================================
FILE: test/assets/shapes_test.twb
================================================
<_.fcp.AnimationOnByDefault.true...AnimationOnByDefault />
<_.fcp.MarkAnimation.true...MarkAnimation />
<_.fcp.ObjectModelEncapsulateLegacy.true...ObjectModelEncapsulateLegacy />
<_.fcp.ObjectModelTableType.true...ObjectModelTableType />
<_.fcp.SchemaViewerObjectModel.true...SchemaViewerObjectModel />
<_.fcp.AnimationOnByDefault.false...style>
<_.fcp.AnimationOnByDefault.false..._.fcp.MarkAnimation.true...style-rule element='animation'>
<_.fcp.AnimationOnByDefault.false...format attr='animation-on' value='ao-on' />
<_.fcp.ObjectModelEncapsulateLegacy.false...relation connection='excel-direct.0ozsbj20cdelf51evvdk71kugqg0' name='Orders' table='[Orders$]' type='table'>
<_.fcp.ObjectModelEncapsulateLegacy.true...relation type='collection'>
0[Orders]Counttrue0"A1:U9995:no:A1:U9995:0"true60[People]Counttrue0"A1:B5:no:A1:B5:0"true60[Returns]Counttrue0"A1:B801:no:A1:B801:0"true6Row ID20[Row ID][Orders]Row ID0integerSumtrue"I8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Order ID130[Order ID][Orders]Order ID1stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Order Date7[Order Date][Orders]Order Date2dateYeartrue"DATE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Ship Date7[Ship Date][Orders]Ship Date3dateYeartrue"DATE"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Ship Mode130[Ship Mode][Orders]Ship Mode4stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Customer ID130[Customer ID][Orders]Customer ID5stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Customer Name130[Customer Name][Orders]Customer Name6stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Segment130[Segment][Orders]Segment7stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Country/Region130[Country/Region][Orders]Country/Region8stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
City130[City][Orders]City9stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
State130[State][Orders]State10stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Postal Code20[Postal Code][Orders]Postal Code11integerSumtrue"I8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Region130[Region][Orders]Region12stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Product ID130[Product ID][Orders]Product ID13stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Category130[Category][Orders]Category14stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Sub-Category130[Sub-Category][Orders]Sub-Category15stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Product Name130[Product Name][Orders]Product Name16stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Sales5[Sales][Orders]Sales17realSum15true"R8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Quantity20[Quantity][Orders]Quantity18integerSumtrue"I8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Discount5[Discount][Orders]Discount19realSum15true"R8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Profit5[Profit][Orders]Profit20realSum15true"R8"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Orders_ECFCA1FB690A41FE803BC071773BA862]
Regional Manager130[Regional Manager][People]Regional Manager21stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[People_D73023733B004CC1B3CB1ACF62F4A965]
Region130[Region (People)][People]Region22stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[People_D73023733B004CC1B3CB1ACF62F4A965]
Returned130[Returned][Returns]Returned23stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Returns_2AA0FE4D737A4F63970131D0E7480A03]
Order ID130[Order ID (Returns)][Returns]Order ID24stringCounttrue"WSTR"
<_.fcp.ObjectModelEncapsulateLegacy.true...object-id>[Returns_2AA0FE4D737A4F63970131D0E7480A03]
"3D Systems Cube Printer, 2nd Generation, Magenta""3D Systems Cube Printer, 2nd Generation, White""3M Hangers With Command Adhesive""3M Office Air Cleaner""3M Organizer Strips""3M Polarizing Light Filter Sleeves""3M Polarizing Task Lamp with Clamp Arm, Light Gray""3M Replacement Filter for Office Air Cleaner for 20' x 33' Room""Acco 3-Hole Punch""Acco 6 Outlet Guardian Basic Surge Suppressor""Acco 6 Outlet Guardian Premium Plus Surge Suppressor""Acco 6 Outlet Guardian Premium Surge Suppressor""Acco 6 Outlet Guardian Standard Surge Suppressor""Acco 7-Outlet Masterpiece Power Center, Wihtout Fax/Phone Line Protection""Acco Banker's Clasps, 5 3/4\"-Long""Acco Clips to Go Binder Clips, 24 Clips in Two Sizes""Acco D-Ring Binder w/DublLock""Acco Data Flex Cable Posts For Top & Bottom Load Binders, 6\" Capacity""Acco Economy Flexible Poly Round Ring Binder""Acco Expandable Hanging Binders""Acco Flexible ACCOHIDE Square Ring Data Binder, Dark Blue, 11 1/2\" X 14\" 7/8\"""Acco Four Pocket Poly Ring Binder with Label Holder, Smoke, 1\"""Acco Glide Clips""Acco Hanging Data Binders""Acco Hot Clips Clips to Go""Acco Perma 2700 Stacking Storage Drawers""Acco Perma 3000 Stacking Storage Drawers""Acco Perma 4000 Stacking Storage Drawers""Acco Pressboard Covers with Storage Hooks, 14 7/8\" x 11\", Dark Blue""Acco Pressboard Covers with Storage Hooks, 14 7/8\" x 11\", Executive Red""Acco Pressboard Covers with Storage Hooks, 14 7/8\" x 11\", Light Blue""Acco Pressboard Covers with Storage Hooks, 9 1/2\" x 11\", Executive Red""Acco PRESSTEX Data Binder with Storage Hooks, Dark Blue, 14 7/8\" X 11\"""Acco PRESSTEX Data Binder with Storage Hooks, Dark Blue, 9 1/2\" X 11\"""Acco PRESSTEX Data Binder with Storage Hooks, Light Blue, 9 1/2\" X 11\"""Acco Recycled 2\" Capacity Laser Printer Hanging Data Binders""Acco Side-Punched Conventional Columnar Pads""Acco Six-Outlet Power Strip, 4' Cord Length""Acco Smartsocket Color-Coded Six-Outlet AC Adapter Model Surge Protectors""Acco Smartsocket Table Surge Protector, 6 Color-Coded Adapter Outlets""Acco Suede Grain Vinyl Round Ring Binder""Acco Translucent Poly Ring Binders""ACCOHIDE 3-Ring Binder, Blue, 1\"""ACCOHIDE Binder by Acco""Accohide Poly Flexible Ring Binders""Acme 10\" Easy Grip Assistive Scissors""Acme 8\" Straight Scissors""Acme Box Cutter Scissors""Acme Design Line 8\" Stainless Steel Bent Scissors w/Champagne Handles, 3-1/8\" Cut""Acme Design Stainless Steel Bent Scissors""Acme Elite Stainless Steel Scissors""Acme Forged Steel Scissors with Black Enamel Handles""Acme Galleria Hot Forged Steel Scissors with Colored Handles""Acme Hot Forged Carbon Steel Scissors with Nickel-Plated Handles, 3 7/8\" Cut, 8\"L""Acme Kleen Earth Office Shears""Acme Kleencut Forged Steel Scissors""Acme Office Executive Series Stainless Steel Trimmers""Acme Preferred Stainless Steel Scissors""Acme Rosewood Handle Letter Opener""Acme Serrated Blade Letter Opener""Acme Softgrip Scissors""Acme Stainless Steel Office Snips""Acme Tagit Stainless Steel Antibacterial Scissors""Acme Titanium Bonded Scissors""Acme Value Line Scissors""Adams \"While You Were Out\" Message Pads""Adams Phone Message Book, 200 Message Capacity, 8 1/16” x 11”""Adams Phone Message Book, Professional, 400 Message Capacity, 5 3/6” x 11”""Adams Telephone Message Book W/Dividers/Space For Phone Numbers, 5 1/4\"X8 1/2\", 200/Messages""Adams Telephone Message Book W/Dividers/Space For Phone Numbers, 5 1/4\"X8 1/2\", 300/Messages""Adams Telephone Message Book w/Frequently-Called Numbers Space, 400 Messages per Book""Adams Telephone Message Books, 5 1/4” x 11”""Adams Write n' Stick Phone Message Book, 11\" X 5 1/4\", 200 Messages""Spiral Phone Message Books with Labels by Adams""Advantus 10-Drawer Portable Organizer, Chrome Metal Frame, Smoke Drawers""Advantus Employee of the Month Certificate Frame, 11 x 13-1/2""Advantus Map Pennant Flags and Round Head Tacks""Advantus Motivational Note Cards""Advantus Panel Wall Acrylic Frame""Advantus Panel Wall Certificate Holder - 8.5x11""Advantus Plastic Paper Clips""Advantus Push Pins""Advantus Push Pins, Aluminum Head""Advantus Rolling Drawer Organizers""Advantus Rolling Storage Box""Advantus SlideClip Paper Clips""Advantus T-Pin Paper Clips""Akro Stacking Bins""Akro-Mils 12-Gallon Tote""Alliance Big Bands Rubber Bands, 12/Pack""Alliance Rubber Bands""Alliance Super-Size Bands, Assorted Sizes""Sterling Rubber Bands by Alliance""Ampad \#10 Peel & Seel Holiday Envelopes""Ampad Evidence Wirebond Steno Books, 6\" x 9\"""Ampad Gold Fibre Wirebound Steno Books, 6\" x 9\", Gregg Ruled""Ampad Phone Message Book, Recycled, 400 Message Capacity, 5 ¾” x 11”""Ampad Poly Cover Wirebound Steno Book, 6\" x 9\" Assorted Colors, Gregg Ruled""Angle-D Binders with Locking Rings, Label Holders""Angle-D Ring Binders""Anker 24W Portable Micro USB Car Charger""Anker 36W 4-Port USB Wall Charger Travel Power Adapter for iPhone 5s 5c 5""Anker Astro 15000mAh USB Portable Charger""Anker Astro Mini 3000mAh Ultra-Compact Portable Charger""Anker Ultra-Slim Mini Bluetooth 3.0 Wireless Keyboard""Anker Ultrathin Bluetooth Wireless Keyboard Aluminum Cover with Stand""Apple EarPods with Remote and Mic""Apple iPhone 5""Apple iPhone 5C""Apple iPhone 5S""Array Memo Cubes""Array Parchment Paper, Assorted Colors""AT&T 1070 Corded Phone""AT&T 1080 Corded phone""AT&T 1080 Phone""AT&T 17929 Lendline Telephone""AT&T 841000 Phone""AT&T CL2909""AT&T CL82213""AT&T CL83451 4-Handset Telephone""AT&T EL51110 DECT""AT&T SB67148 SynJ""AT&T TR1909W""Ativa D5772 2-Line 5.8GHz Digital Expandable Corded/Cordless Phone System with Answering & Caller ID/Call Waiting, Black/Silver""Ativa MDM8000 8-Sheet Micro-Cut Shredder""Ativa V4110MDD Micro-Cut Shredder""Atlantic Metals Mobile 2-Shelf Bookcases, Custom Colors""Atlantic Metals Mobile 3-Shelf Bookcases, Custom Colors""Atlantic Metals Mobile 4-Shelf Bookcases, Custom Colors""Atlantic Metals Mobile 5-Shelf Bookcases, Custom Colors""Avanti 1.7 Cu. Ft. Refrigerator""Avanti 4.4 Cu. Ft. Refrigerator""Avaya 4621SW VoIP phone""Avaya 5410 Digital phone""Avaya 5420 Digital phone""Avaya IP Phone 1140E VoIP phone""Avery 05222 Permanent Self-Adhesive File Folder Labels for Typewriters, on Rolls, White, 250/Roll""Avery 3 1/2\" Diskette Storage Pages, 10/Pack""Avery 4027 File Folder Labels for Dot Matrix Printers, 5000 Labels per Box, White""Avery 473""Avery 474""Avery 475""Avery 476""Avery 477""Avery 478""Avery 479""Avery 48""Avery 480""Avery 481""Avery 482""Avery 483""Avery 484""Avery 485""Avery 486""Avery 487""Avery 488""Avery 489""Avery 49""Avery 490""Avery 491""Avery 492""Avery 493""Avery 494""Avery 495""Avery 496""Avery 497""Avery 498""Avery 499""Avery 5""Avery 50""Avery 500""Avery 501""Avery 502""Avery 503""Avery 504""Avery 505""Avery 506""Avery 507""Avery 508""Avery 509""Avery 51""Avery 510""Avery 511""Avery 512""Avery 513""Avery 514""Avery 515""Avery 516""Avery 517""Avery 518""Avery 519""Avery 52""Avery 520""Avery Address/Shipping Labels for Typewriters, 4\" x 2\"""Avery Arch Ring Binders""Avery Binder Labels""Avery Binding System Hidden Tab Executive Style Index Sets""Avery Durable Binders""Avery Durable Plastic 1\" Binders""Avery Durable Poly Binders""Avery Durable Slant Ring Binders""Avery Durable Slant Ring Binders With Label Holder""Avery Durable Slant Ring Binders, No Labels""Avery File Folder Labels""Avery Flip-Chart Easel Binder, Black""Avery Fluorescent Highlighter Four-Color Set""Avery Framed View Binder, EZD Ring (Locking), Navy, 1 1/2\"""Avery Hanging File Binders""Avery Heavy-Duty EZD Binder With Locking Rings""Avery Heavy-Duty EZD View Binder with Locking Rings""Avery Hi-Liter Comfort Grip Fluorescent Highlighter, Yellow Ink""Avery Hi-Liter EverBold Pen Style Fluorescent Highlighters, 4/Pack""Avery Hi-Liter Fluorescent Desk Style Markers""Avery Hi-Liter GlideStik Fluorescent Highlighter, Yellow Ink""Avery Hi-Liter Pen Style Six-Color Fluorescent Set""Avery Hi-Liter Smear-Safe Highlighters""Avery Hidden Tab Dividers for Binding Systems""Avery Hole Reinforcements""Avery Legal 4-Ring Binder""Avery Metallic Poly Binders""Avery Non-Stick Binders""Avery Non-Stick Heavy Duty View Round Locking Ring Binders""Avery Personal Creations Heavyweight Cards""Avery Poly Binder Pockets""Avery Premier Heavy-Duty Binder with Round Locking Rings""Avery Printable Repositionable Plastic Tabs""Avery Recycled Flexi-View Covers for Binding Systems""Avery Reinforcements for Hole-Punch Pages""Avery Round Ring Poly Binders""Avery Self-Adhesive Photo Pockets for Polaroid Photos""Avery Trapezoid Extra Heavy Duty 4\" Binders""Avery Trapezoid Ring Binder, 3\" Capacity, Black, 1040 sheets""Avery Triangle Shaped Sheet Lifters, Black, 2/Pack""Avery White Multi-Purpose Labels""Black Avery Memo-Size 3-Ring Binder, 5 1/2\" x 8 1/2\"""Balt Solid Wood Rectangular Table""Balt Solid Wood Round Tables""Balt Split Level Computer Training Table""Barricks 18\" x 48\" Non-Folding Utility Table with Bottom Storage Shelf""Barricks Non-Folding Utility Table with Steel Legs, Laminate Tops""Belkin 19\" Center-Weighted Shelf, Gray""Belkin 19\" Vented Equipment Shelf, Black""Belkin 325VA UPS Surge Protector, 6'""Belkin 5 Outlet SurgeMaster Power Centers""Belkin 6 Outlet Metallic Surge Strip""Belkin 7 Outlet SurgeMaster II""Belkin 7 Outlet SurgeMaster Surge Protector with Phone Protection""Belkin 7-Outlet SurgeMaster Home Series""Belkin 8 Outlet Surge Protector""Belkin 8 Outlet SurgeMaster II Gold Surge Protector""Belkin 8 Outlet SurgeMaster II Gold Surge Protector with Phone Protection""Belkin 8-Outlet Premiere SurgeMaster II Surge Protectors""Belkin F5C206VTEL 6 Outlet Surge""Belkin F8E887 USB Wired Ergonomic Keyboard""Belkin F9G930V10-GRY 9 Outlet Surge""Belkin F9H710-06 7 Outlet SurgeMaster Surge Protector""Belkin F9M820V08 8 Outlet Surge""Belkin F9S820V06 8 Outlet Surge""Belkin Grip Candy Sheer Case / Cover for iPhone 5 and 5S""Belkin iPhone and iPad Lightning Cable""Belkin OmniView SE Rackmount Kit""Belkin Premiere Surge Master II 8-outlet surge protector""Belkin QODE FastFit Bluetooth Keyboard""Belkin SportFit Armband For iPhone 5s/5c, Fuchsia""Belkin Standard 104 key USB Keyboard""Berol Giant Pencil Sharpener""Bestar Classic Bookcase""Bevis 36 x 72 Conference Tables""Bevis 44 x 96 Conference Tables""Bevis Boat-Shaped Conference Table""Bevis Oval Conference Table, Walnut""Bevis Rectangular Conference Tables""Bevis Round Bullnose 29\" High Table Top""Bevis Round Conference Room Tables and Bases""Bevis Round Conference Table Top & Single Column Base""Bevis Round Conference Table Top, X-Base""Bevis Steel Folding Chairs""Bevis Traditional Conference Table Top, Plinth Base""BIC Brite Liner Grip Highlighters""BIC Brite Liner Grip Highlighters, Assorted, 5/Pack""BIC Brite Liner Highlighters""BIC Brite Liner Highlighters, Chisel Tip""BIC Liqua Brite Liner""Binney & Smith Crayola Metallic Colored Pencils, 8-Color Set""Binney & Smith Crayola Metallic Crayons, 16-Color Pack""Binney & Smith inkTank Desk Highlighter, Chisel Tip, Yellow, 12/Box""Binney & Smith inkTank Erasable Desk Highlighter, Chisel Tip, Yellow, 12/Box""Binney & Smith inkTank Erasable Pocket Highlighter, Chisel Tip, Yellow""Bionaire 99.97\% HEPA Air Cleaner""Bionaire Personal Warm Mist Humidifier/Vaporizer""Boston 1645 Deluxe Heavier-Duty Electric Pencil Sharpener""Boston 16701 Slimline Battery Pencil Sharpener""Boston 16750 Black Compact Battery Pencil Sharpener""Boston 16765 Mini Stand Up Battery Pencil Sharpener""Boston 16801 Nautilus Battery Pencil Sharpener""Boston 1730 StandUp Electric Pencil Sharpener""Boston 1799 Powerhouse Electric Pencil Sharpener""Boston 1827 Commercial Additional Cutter, Drive Gear & Gear Rack for 1606""Boston 1900 Electric Pencil Sharpener""Boston 19500 Mighty Mite Electric Pencil Sharpener""Boston Electric Pencil Sharpener, Model 1818, Charcoal Black""Boston Heavy-Duty Trimline Electric Pencil Sharpeners""Boston Home & Office Model 2000 Electric Pencil Sharpeners""Boston KS Multi-Size Manual Pencil Sharpener""Boston Model 1800 Electric Pencil Sharpener, Gray""BOSTON Model 1800 Electric Pencil Sharpeners, Putty/Woodgrain""BOSTON Ranger \#55 Pencil Sharpener, Black""Boston School Pro Electric Pencil Sharpener, 1670""Bretford “Just In Time” Height-Adjustable Multi-Task Work Tables""Bretford CR4500 Series Slim Rectangular Table""Bretford CR8500 Series Meeting Room Furniture""Bretford Rectangular Conference Table Tops""Brother DCP1000 Digital 3 in 1 Multifunction Machine""Brother IntelliFAX-2840 Laser Fax""Brother IntelliFAX-5750e Plain Paper Fax Machine""Brother MFC-9340CDW LED All-In-One Printer, Copier Scanner""Brother MFC-J470DW Inkjet All-In-One Printer, Copier, Scanner""Bulldog Table or Wall-Mount Pencil Sharpener""Bulldog Vacuum Base Pencil Sharpener""Bush Advantage Collection Racetrack Conference Table""Bush Advantage Collection Round Conference Table""Bush Andora Bookcase, Maple/Graphite Gray Finish""Bush Andora Conference Table, Maple/Graphite Gray Finish""Bush Birmingham Collection Bookcase, Dark Cherry""Bush Cubix Collection Bookcases, Fully Assembled""Bush Cubix Conference Tables, Fully Assembled""Bush Heritage Pine Collection 5-Shelf Bookcase, Albany Pine Finish, *Special Order""Bush Mission Pointe Library""Bush Saratoga Collection 5-Shelf Bookcase, Hanover Cherry, *Special Order""Bush Somerset Collection Bookcase""Bush Westfield Collection Bookcases, Dark Cherry Finish""Bush Westfield Collection Bookcases, Medium Cherry Finish""C-Line Cubicle Keepers Polyproplyene Holder w/Velcro Back, 8-1/2x11, 25/Bx""C-Line Cubicle Keepers Polyproplyene Holder With Velcro Backings""C-Line Magnetic Cubicle Keepers, Clear Polypropylene""C-Line Peel & Stick Add-On Filing Pockets, 8-3/4 x 5-1/8, 10/Pack""Canon Color ImageCLASS MF8580Cdw Wireless Laser All-In-One Printer, Copier, Scanner""Canon Image Class D660 Copier""Canon imageCLASS 2200 Advanced Copier""Canon Imageclass D680 Copier / Fax""Canon imageCLASS MF7460 Monochrome Digital Laser Multifunction Copier""Canon PC-428 Personal Copier""Canon PC1060 Personal Laser Copier""Canon PC1080F Personal Copier""Canon PC170 Desktop Personal Copier""Canon PC940 Copier""Cardinal EasyOpen D-Ring Binders""Cardinal Hold-It CD Pocket""Cardinal Holdit Business Card Pockets""Cardinal Holdit Data Disk Pockets""Cardinal HOLDit! Binder Insert Strips,Extra Strips""Cardinal Poly Pocket Divider Pockets for Ring Binders""Cardinal Slant-D Ring Binder, Heavy Gauge Vinyl""Cardinal Slant-D Ring Binders""Carina 42\"Hx23 3/4\"W Media Storage Unit""Carina Double Wide Media Storage Towers in Natural & Black""Carina Media Storage Towers in Natural & Black""Carina Mini System Audio Rack, Model AR050B""Chromcraft 48\" x 96\" Racetrack Double Pedestal Table""Chromcraft Bull-Nose Wood 48\" x 96\" Rectangular Conference Tables""Chromcraft Bull-Nose Wood Oval Conference Tables & Bases""Chromcraft Bull-Nose Wood Round Conference Table Top, Wood Base""Chromcraft Rectangular Conference Tables""Chromcraft Round Conference Tables""Cisco 7975G IP Phone""Cisco 8961 IP Phone Charcoal""Cisco 8x8 Inc. 6753i IP Business Phone System""Cisco 9971 IP Video Phone Charcoal""Cisco CP-7936 Unified IP Conference Station Phone""Cisco CP-7937G Unified IP Conference Station Phone""Cisco Desktop Collaboration Experience DX650 IP Video Phone""Cisco IP Phone 7961G VoIP phone - Dark gray""Cisco IP Phone 7961G-GE VoIP phone""Cisco Small Business SPA 502G VoIP phone""Cisco SPA 501G IP Phone""Cisco SPA 502G IP Phone""Cisco SPA112 2 Port Phone Adapter""Cisco SPA301""Cisco SPA508G""Cisco SPA525G2 5-Line IP Phone""Cisco SPA525G2 IP Phone - Wireless""Cisco TelePresence System EX90 Videoconferencing Unit""Cisco Unified IP Phone 7945G VoIP phone""ClearOne CHATAttach 160 - speaker phone""ClearOne Communications CHAT 70 OC Speaker Phone""Clearsounds A400""ClearSounds CSC500 Amplified Spirit Phone Corded phone""Crayola Anti Dust Chalk, 12/Pack""Crayola Colored Pencils""Cubify CubeX 3D Printer Double Head Print""Cubify CubeX 3D Printer Triple Head Print""Dana Fluorescent Magnifying Lamp, White, 36\"""Dana Halogen Swing-Arm Architect Lamp""Dana Swing-Arm Lamps""DAX Black Cherry Wood-Tone Poster Frame""DAX Charcoal/Nickel-Tone Document Frame, 5 x 7""Dax Clear Box Frame""DAX Clear Channel Poster Frame""DAX Contemporary Wood Frame with Silver Metal Mat, Desktop, 11 x 14 Size""DAX Copper Panel Document Frame, 5 x 7 Size""DAX Cubicle Frames - 8x10""DAX Cubicle Frames, 8-1/2 x 11""DAX Executive Solid Wood Document Frame, Desktop or Hang, Mahogany, 5 x 7""DAX Metal Frame, Desktop, Stepped-Edge""DAX Natural Wood-Tone Poster Frame""DAX Solid Wood Frames""DAX Two-Tone Rosewood/Black Document Frame, Desktop, 5 x 7""DAX Two-Tone Silver Metal Document Frame""DAX Value U-Channel Document Frames, Easel Back""DAX Wood Document Frame""DAX Wood Document Frame.""Decoflex Hanging Personal Folder File""Decoflex Hanging Personal Folder File, Blue""Deflect-o DuraMat Antistatic Studded Beveled Mat for Medium Pile Carpeting""Deflect-o DuraMat Lighweight, Studded, Beveled Mat for Low Pile Carpeting""Deflect-o EconoMat Nonstudded, No Bevel Mat""Deflect-o EconoMat Studded, No Bevel Mat for Low Pile Carpeting""Deflect-o Glass Clear Studded Chair Mats""Deflect-O Glasstique Clear Desk Accessories""Deflect-o RollaMat Studded, Beveled Mat for Medium Pile Carpeting""Deflect-o SuperTray Unbreakable Stackable Tray, Letter, Black""Dixon My First Ticonderoga Pencil, \#2""DIXON Oriole Pencils""Dixon Prang Watercolor Pencils, 10-Color Set with Brush""Dixon Ticonderoga Core-Lock Colored Pencils""Dixon Ticonderoga Core-Lock Colored Pencils, 48-Color Set""DIXON Ticonderoga Erasable Checking Pencils""Dixon Ticonderoga Erasable Colored Pencil Set, 12-Color""Dixon Ticonderoga Maple Cedar Pencil, \#2""Dixon Ticonderoga Pencils""DMI Arturo Collection Mission-style Design Wood Chair""DMI Eclipse Executive Suite Bookcases""DXL Angle-View Binders with Locking Rings by Samsill""DXL Angle-View Binders with Locking Rings, Black""Eldon \"L\" Workstation Diamond Chairmat""Eldon 100 Class Desk Accessories""Eldon 200 Class Desk Accessories""Eldon 200 Class Desk Accessories, Black""Eldon 200 Class Desk Accessories, Burgundy""Eldon 200 Class Desk Accessories, Smoke""Eldon 300 Class Desk Accessories, Black""Eldon 400 Class Desk Accessories, Black Carbon""Eldon 500 Class Desk Accessories""Eldon Advantage Chair Mats for Low to Medium Pile Carpets""Eldon Advantage Foldable Chair Mats for Low Pile Carpets""Eldon Antistatic Chair Mats for Low to Medium Pile Carpets""Eldon Base for stackable storage shelf, platinum""Eldon Cleatmat Chair Mats for Medium Pile Carpets""Eldon Cleatmat Plus Chair Mats for High Pile Carpets""Eldon ClusterMat Chair Mat with Cordless Antistatic Protection""Eldon Delta Triangular Chair Mat, 52\" x 58\", Clear""Eldon Econocleat Chair Mats for Low Pile Carpets""Eldon Executive Woodline II Cherry Finish Desk Accessories""Eldon Executive Woodline II Desk Accessories, Mahogany""Eldon Expressions Desk Accessory, Wood Pencil Holder, Oak""Eldon Expressions Desk Accessory, Wood Photo Frame, Mahogany""Eldon Expressions Mahogany Wood Desk Collection""Eldon Expressions Punched Metal & Wood Desk Accessories, Black & Cherry""Eldon Expressions Punched Metal & Wood Desk Accessories, Pewter & Cherry""Eldon Expressions Wood and Plastic Desk Accessories, Cherry Wood""Eldon Expressions Wood and Plastic Desk Accessories, Oak""Eldon Expressions Wood Desk Accessories, Oak""Eldon File Chest Portable File""Eldon Fold 'N Roll Cart System""Eldon Gobal File Keepers""Eldon Image Series Black Desk Accessories""Eldon Image Series Desk Accessories, Burgundy""Eldon Imàge Series Desk Accessories, Clear""Eldon Image Series Desk Accessories, Ebony""Eldon Jumbo ProFile Portable File Boxes Graphite/Black""Eldon Mobile Mega Data Cart Mega Stackable Add-On Trays""Eldon Pizzaz Desk Accessories""Eldon Portable Mobile Manager""Eldon ProFile File 'N Store Portable File Tub Letter/Legal Size Black""Eldon Radial Chair Mat for Low to Medium Pile Carpets""Eldon Regeneration Recycled Desk Accessories, Black""Eldon Regeneration Recycled Desk Accessories, Smoke""Eldon Shelf Savers Cubes and Bins""Eldon Simplefile Box Office""Eldon Spacemaker Box, Quick-Snap Lid, Clear""Eldon Stackable Tray, Side-Load, Legal, Smoke""Eldon Wave Desk Accessories""Electrix 20W Halogen Replacement Bulb for Zoom-In Desk Lamp""Electrix Architect's Clamp-On Swing Arm Lamp, Black""Electrix Fluorescent Magnifier Lamps & Weighted Base""Electrix Halogen Magnifier Lamp""Electrix Incandescent Magnifying Lamp, Black""Enermax Acrylux Wireless Keyboard""Enermax Aurora Lite Keyboard""Enermax Briskie RF Wireless Keyboard and Mouse Combo""Epson Perfection V600 Photo Scanner""Epson TM-T88V Direct Thermal Printer - Monochrome - Desktop""Epson WorkForce WF-2530 All-in-One Printer, Copier Scanner""Eureka Disposable Bags for Sanitaire Vibra Groomer I Upright Vac""Eureka Hand Vacuum, Bagless""Eureka Recycled Copy Paper 8 1/2\" x 11\", Ream""Eureka Sanitaire Commercial Upright""Eureka Sanitaire Multi-Pro Heavy-Duty Upright, Disposable Bags""Eureka The Boss Cordless Rechargeable Stick Vac""Eureka The Boss Lite 10-Amp Upright Vacuum, Blue""Eureka The Boss Plus 12-Amp Hard Box Upright Vacuum, Red""Euro Pro Shark Stick Mini Vacuum""Euro-Pro Shark Turbo Vacuum""Executive Impressions 10\" Spectator Wall Clock""Executive Impressions 12\" Wall Clock""Executive Impressions 13-1/2\" Indoor/Outdoor Wall Clock""Executive Impressions 13\" Chairman Wall Clock""Executive Impressions 13\" Clairmont Wall Clock""Executive Impressions 14\"""Executive Impressions 14\" Contract Wall Clock""Executive Impressions 14\" Contract Wall Clock with Quartz Movement""Executive Impressions 14\" Two-Color Numerals Wall Clock""Executive Impressions 16-1/2\" Circular Wall Clock""Executive Impressions 8-1/2\" Career Panel/Partition Cubicle Clock""Executive Impressions Supervisor Wall Clock""Fellowes 8 Outlet Superior Workstation Surge Protector""Fellowes 8 Outlet Superior Workstation Surge Protector w/o Phone/Fax/Modem Protection""Fellowes Advanced 8 Outlet Surge Suppressor with Phone/Fax Protection""Fellowes Advanced Computer Series Surge Protectors""Fellowes Bankers Box Recycled Super Stor/Drawer""Fellowes Bankers Box Staxonsteel Drawer File/Stacking System""Fellowes Bankers Box Stor/Drawer Steel Plus""Fellowes Bases and Tops For Staxonsteel/High-Stak Systems""Fellowes Basic Home/Office Series Surge Protectors""Fellowes Binding Cases""Fellowes Black Plastic Comb Bindings""Fellowes Command Center 5-outlet power strip""Fellowes Desktop Hanging File Manager""Fellowes Econo/Stor Drawers""Fellowes High-Stak Drawer Files""Fellowes Mighty 8 Compact Surge Protector""Fellowes Mobile File Cart, Black""Fellowes Neat Ideas Storage Cubes""Fellowes Officeware Wire Shelving""Fellowes PB200 Plastic Comb Binding Machine""Fellowes PB300 Plastic Comb Binding Machine""Fellowes PB500 Electric Punch Plastic Comb Binding Machine with Manual Bind""Fellowes Personal Hanging Folder Files, Navy""Fellowes Powershred HS-440 4-Sheet High Security Shredder""Fellowes Premier Superior Surge Suppressor, 10-Outlet, With Phone and Remote""Fellowes Presentation Covers for Comb Binding Machines""Fellowes Recycled Storage Drawers""Fellowes Smart Surge Ten-Outlet Protector, Platinum""Fellowes Staxonsteel Drawer Files""Fellowes Stor/Drawer Steel Plus Storage Drawers""Fellowes Strictly Business Drawer File, Letter/Legal Size""Fellowes Super Stor/Drawer""Fellowes Super Stor/Drawer Files""Fellowes Superior 10 Outlet Split Surge Protector""Fellowes Twister Kit, Gray/Clear, 3/pkg""First Data FD10 PIN Pad""First Data TMFD35 PIN Pad""Fiskars 8\" Scissors, 2/Pack""Fiskars Home & Office Scissors""Fiskars Softgrip Scissors""Fiskars Spring-Action Scissors""G.E. Halogen Desk Lamp Bulbs""G.E. Longer-Life Indoor Recessed Floodlight Bulbs""GBC Binding covers""GBC Clear Cover, 8-1/2 x 11, unpunched, 25 covers per pack""GBC DocuBind 200 Manual Binding Machine""GBC DocuBind 300 Electric Binding Machine""GBC DocuBind P100 Manual Binding Machine""GBC DocuBind P400 Electric Binding System""GBC DocuBind P50 Personal Binding Machine""GBC DocuBind TL200 Manual Binding Machine""GBC DocuBind TL300 Electric Binding System""GBC Durable Plastic Covers""GBC Ibimaster 500 Manual ProClick Binding System""GBC Imprintable Covers""GBC Instant Index System for Binding Systems""GBC Instant Report Kit""GBC Laser Imprintable Binding System Covers, Desert Sand""GBC Linen Binding Covers""GBC Personal VeloBind Strips""GBC Plastic Binding Combs""GBC Plasticlear Binding Covers""GBC Poly Designer Binding Covers""GBC Pre-Punched Binding Paper, Plastic, White, 8-1/2\" x 11\"""GBC Premium Transparent Covers with Diagonal Lined Pattern""GBC Prepunched Paper, 19-Hole, for Binding Systems, 24-lb""GBC Prestige Therm-A-Bind Covers""GBC ProClick 150 Presentation Binding System""GBC ProClick Punch Binding System""GBC ProClick Spines for 32-Hole Punch""GBC Recycled Grain Textured Covers""GBC Recycled Regency Composition Covers""GBC Recycled VeloBinder Covers""GBC Standard Plastic Binding Systems Combs""GBC Standard Plastic Binding Systems' Combs""GBC Standard Recycled Report Covers, Clear Plastic Sheets""GBC Standard Therm-A-Bind Covers""GBC Therma-A-Bind 250T Electric Binding System""GBC Twin Loop Wire Binding Elements""GBC Twin Loop Wire Binding Elements, 9/16\" Spine, Black""GBC VeloBind Cover Sets""GBC Velobind Prepunched Cover Sets, Regency Series""GBC VeloBinder Electric Binding Machine""GBC VeloBinder Manual Binding System""GBC VeloBinder Strips""GBC White Gloss Covers, Plain Front""GBC Wire Binding Combs""GBC Wire Binding Strips""GE 2-Jack Phone Line Splitter""GE 30524EE4""GE 4 Foot Flourescent Tube, 40 Watt""GE 48\" Fluorescent Tube, Cool White Energy Saver, 34 Watts, 30/Box""GE DSL Phone Line Filter""GE General Purpose, Extra Long Life, Showcase & Floodlight Incandescent Bulbs""GE General Use Halogen Bulbs, 100 Watts, 1 Bulb per Pack""Global Adaptabilites Bookcase, Cherry/Storm Gray Finish""Global Adaptabilities Conference Tables""Global Airflow Leather Mesh Back Chair, Black""Global Armless Task Chair, Royal Blue""Global Chrome Stack Chair""Global Comet Stacking Arm Chair""Global Comet Stacking Armless Chair""Global Commerce Series High-Back Swivel/Tilt Chairs""Global Commerce Series Low-Back Swivel/Tilt Chairs""Global Deluxe High-Back Manager's Chair""Global Deluxe High-Back Office Chair in Storm""Global Deluxe Office Fabric Chairs""Global Deluxe Stacking Chair, Gray""Global Deluxe Steno Chair""Global Enterprise Series Seating High-Back Swivel/Tilt Chairs""Global Enterprise Series Seating Low-Back Swivel/Tilt Chairs""Global Ergonomic Managers Chair""Global Executive Mid-Back Manager's Chair""Global Fabric Manager's Chair, Dark Gray""Global Geo Office Task Chair, Gray""Global High-Back Leather Tilter, Burgundy""Global Highback Leather Tilter in Burgundy""Global Italian Leather Office Chair""Global Leather & Oak Executive Chair, Burgundy""Global Leather and Oak Executive Chair, Black""Global Leather Executive Chair""Global Leather Highback Executive Chair with Pneumatic Height Adjustment, Black""Global Leather Task Chair, Black""Global Low Back Tilter Chair""Global Manager's Adjustable Task Chair, Storm""Global Push Button Manager's Chair, Indigo""Global Stack Chair with Arms, Black""Global Stack Chair without Arms, Black""Global Super Steno Chair""Global Task Chair, Black""Global Troy Executive Leather Low-Back Tilter""Global Value Mid-Back Manager's Chair, Gray""Global Value Steno Chair, Gray""Global Wood Trimmed Manager's Task Chair, Khaki""Globe Weis Peel & Seel First Class Envelopes""Gould Plastics 18-Pocket Panel Bin, 34w x 5-1/4d x 20-1/2h""Gould Plastics 9-Pocket Panel Bin, 18-3/8w x 5-1/4d x 20-1/2h, Black""Grandstream GXP1160 VoIP phone""Grandstream GXP2100 Mainstream Business Phone""Griffin GC17055 Auxiliary Audio Cable""Griffin GC36547 PowerJolt SE Lightning Charger""Hammermill Color Copier Paper (28Lb. and 96 Bright)""Hammermill CopyPlus Copy Paper (20Lb. and 84 Bright)""Harmony Air Purifier""Harmony HEPA Quiet Air Purifiers""Hewlett Packard 310 Color Digital Copier""Hewlett Packard 610 Color Digital Copier / Printer""Hewlett Packard LaserJet 3310 Copier""Hewlett-Packard 300S Scientific Calculator""Hewlett-Packard Deskjet 3050a All-in-One Color Inkjet Printer""Hewlett-Packard Deskjet 5550 Printer""Hewlett-Packard Deskjet 6540 Color Inkjet Printer""Hewlett-Packard Deskjet D4360 Printer""Hewlett-Packard Deskjet F4180 All-in-One Color Ink-jet - Printer / copier / scanner""Hewlett-Packard Desktjet 6988DT Refurbished Printer""HP Designjet T1500 PostScript Inkjet Large Format Printer - 914mm""HP Designjet T520 Inkjet Large Format Printer - 24\" Color""Holmes 99\% HEPA Air Purifier""Holmes Cool Mist Humidifier for the Whole House with 8-Gallon Output per Day, Extended Life Filter""Holmes HEPA Air Purifier""Holmes Odor Grabber""Holmes Replacement Filter for HEPA Air Cleaner, Large Room""Holmes Replacement Filter for HEPA Air Cleaner, Medium Room""Holmes Replacement Filter for HEPA Air Cleaner, Very Large Room, HEPA Filter""Holmes Visible Mist Ultrasonic Humidifier with 2.3-Gallon Output per Day, Replacement Filter""Hon 2090 “Pillow Soft” Series Mid Back Swivel/Tilt Chairs""Hon 2111 Invitation Series Corner Table""Hon 2111 Invitation Series Straight Table""Hon 30\" x 60\" Table with Locking Drawer""Hon 4-Shelf Metal Bookcases""Hon 4060 Series Tables""Hon 4070 Series Pagoda Armless Upholstered Stacking Chairs""Hon 4070 Series Pagoda Round Back Stacking Chairs""Hon 4700 Series Mobuis Mid-Back Task Chairs with Adjustable Arms""Hon 5100 Series Wood Tables""HON 5400 Series Task Chairs for Big and Tall""Hon 61000 Series Interactive Training Tables""Hon 94000 Series Round Tables""Hon Comfortask Task/Swivel Chairs""Hon Deluxe Fabric Upholstered Stacking Chairs""Hon Deluxe Fabric Upholstered Stacking Chairs, Rounded Back""Hon Deluxe Fabric Upholstered Stacking Chairs, Squared Back""Hon Every-Day Chair Series Swivel Task Chairs""Hon Every-Day Series Multi-Task Chairs""Hon GuestStacker Chair""Hon iLevel Computer Training Table""Hon Metal Bookcases, Black""Hon Metal Bookcases, Gray""Hon Metal Bookcases, Putty""Hon Mobius Operator's Chair""Hon Multipurpose Stacking Arm Chairs""Hon Non-Folding Utility Tables""Hon Olson Stacker Chairs""Hon Olson Stacker Stools""Hon Pagoda Stacking Chairs""Hon Practical Foundations 30 x 60 Training Table, Light Gray/Charcoal""Hon Racetrack Conference Tables""Hon Rectangular Conference Tables""Hon Valutask Swivel Chairs""Honeywell Enviracaire Portable Air Cleaner for up to 8 x 10 Room""Honeywell Enviracaire Portable HEPA Air Cleaner for 16' x 20' Room""Honeywell Enviracaire Portable HEPA Air Cleaner for 17' x 22' Room""Honeywell Enviracaire Portable HEPA Air Cleaner for up to 10 x 16 Room""Honeywell Quietcare HEPA Air Cleaner""Hoover Commercial Lightweight Upright Vacuum""Hoover Commercial Lightweight Upright Vacuum with E-Z Empty Dirt Cup""Hoover Commercial Soft Guard Upright Vacuum And Disposable Filtration Bags""Hoover Commercial SteamVac""Hoover Portapower Portable Vacuum""Hoover Replacement Belt for Commercial Guardsman Heavy-Duty Upright Vacuum""Hoover Replacement Belts For Soft Guard & Commercial Ltweight Upright Vacs, 2/Pk""Hoover Shoulder Vac Commercial Portable Vacuum""Hoover Upright Vacuum With Dirt Cup""Hoover WindTunnel Plus Canister Vacuum""Howard Miller 11-1/2\" Diameter Brentwood Wall Clock""Howard Miller 11-1/2\" Diameter Grantwood Wall Clock""Howard Miller 11-1/2\" Diameter Ridgewood Wall Clock""Howard Miller 12-3/4 Diameter Accuwave DS Wall Clock""Howard Miller 12\" Round Wall Clock""Howard Miller 13-1/2\" Diameter Rosebrook Wall Clock""Howard Miller 13-3/4\" Diameter Brushed Chrome Round Wall Clock""Howard Miller 13\" Diameter Goldtone Round Wall Clock""Howard Miller 13\" Diameter Pewter Finish Round Wall Clock""Howard Miller 14-1/2\" Diameter Chrome Round Wall Clock""Howard Miller 16\" Diameter Gallery Wall Clock""Howard Miller Distant Time Traveler Alarm Clock""HP Office Paper (20Lb. and 87 Bright)""HP Office Recycled Paper (20Lb. and 87 Bright)""HP Officejet Pro 8600 e-All-In-One Printer, Copier, Scanner, Fax""HP Standard 104 key PS/2 Keyboard""HTC One""HTC One Mini""Hunt BOSTON Model 1606 High-Volume Electric Pencil Sharpener, Beige""Hunt Boston Vacuum Mount KS Pencil Sharpener""Hunt BOSTON Vista Battery-Operated Pencil Sharpener, Black""Hunt PowerHouse Electric Pencil Sharpener, Blue""Ibico Covers for Plastic or Wire Binding Elements""Ibico EB-19 Dual Function Manual Binding System""Ibico EPK-21 Electric Binding System""Ibico Hi-Tech Manual Binding System""Ibico Ibimaster 300 Manual Binding System""Ibico Laser Imprintable Binding System Covers""Ibico Plastic and Wire Spiral Binding Combs""Ibico Plastic Spiral Binding Combs""Ibico Presentation Index for Binding Systems""Ibico Recycled Grain-Textured Covers""Ibico Recycled Linen-Style Covers""Ibico Standard Transparent Covers""Iceberg Mobile Mega Data/Printer Cart""Iceberg Nesting Folding Chair, 19w x 6d x 43h""Iceberg OfficeWorks 42\" Round Tables""Imation 16GB Mini TravelDrive USB 2.0 Flash Drive""Imation 30456 USB Flash Drive 8GB""Imation 32GB Pocket Pro USB 3.0 Flash Drive - 32 GB - Black - 1 P ...""Imation 8gb Micro Traveldrive Usb 2.0 Flash Drive""Imation Bio 2GB USB Flash Drive Imation Corp""Imation Bio 8GB USB Flash Drive Imation Corp""Imation Clip USB flash drive - 8 GB""Imation Secure Drive + Hardware Encrypted USB flash drive - 16 GB""Imation Secure+ Hardware Encrypted USB 2.0 Flash Drive; 16GB""Imation Swivel Flash Drive USB flash drive - 8 GB""Imation USB 2.0 Swivel Flash Drive USB flash drive - 4 GB - Pink""iOttie HLCRIO102 Car Mount""iOttie XL Car Mount""Iris 3-Drawer Stacking Bin, Black""Iris Project Case""Jabra BIZ 2300 Duo QD Duo Corded Headset""Jabra SPEAK 410""Jabra SPEAK 410 Multidevice Speakerphone""Jabra Supreme Plus Driver Edition Headset""Jawbone JAMBOX Wireless Bluetooth Speaker""Jawbone MINI JAMBOX Wireless Bluetooth Speaker""Kensington 4 Outlet MasterPiece Compact Power Control Center""Kensington 6 Outlet Guardian Standard Surge Protector""Kensington 6 Outlet MasterPiece HOMEOFFICE Power Control Center""Kensington 6 Outlet SmartSocket Surge Protector""Kensington 7 Outlet MasterPiece HOMEOFFICE Power Control Center""Kensington 7 Outlet MasterPiece Power Center""Kensington 7 Outlet MasterPiece Power Center with Fax/Phone Line Protection""Kensington Expert Mouse Optical USB Trackball for PC or Mac""Kensington K72356US Mouse-in-a-Box USB Desktop Mouse""Kensington Orbit Wireless Mobile Trackball for PC and Mac""Kensington SlimBlade Notebook Wireless Mouse with Nano Receiver""KeyTronic 6101 Series - Keyboard - Black""KeyTronic E03601U1 - Keyboard - Beige""KeyTronic KT400U2 - Keyboard - Black""KeyTronic KT800P2 - Keyboard - Black""KI Adjustable-Height Table""KI Conference Tables""Kingston Digital DataTraveler 16GB USB 2.0""Kingston Digital DataTraveler 32GB USB 2.0""Kingston Digital DataTraveler 64GB USB 2.0""Kingston Digital DataTraveler 8GB USB 2.0""Lesro Round Back Collection Coffee Table, End Table""Lesro Sheffield Collection Coffee Table, End Table, Center Table, Corner Table""Lexmark 160 GB Internal Hard Drive""Lexmark 20R1285 X6650 Wireless All-in-One Printer""Lexmark Intuition S505 All-in-One Color Inkjet Printer""Lexmark MarkNet N8150 Wireless Print Server""Lexmark S315 Color Inkjet Printer""Lexmark X 9575 Professional All-in-One Color Printer""Lexmark X8350 All-in-One Color Inkjet Printer""LG Electronics Tone+ HBS-730 Bluetooth Headset""LG G2""LG G3""Linden 10\" Round Wall Clock, Black""Linden 12\" Wall Clock With Oak Frame""Logitech 910-002974 M325 Wireless Mouse for Web Scrolling""Logitech B530 USB Headset - headset - Full size, Binaural""Logitech ClearChat Comfort/USB Headset H390""Logitech Desktop MK120 Mouse and keyboard Combo""Logitech diNovo Edge Keyboard""Logitech G105 Gaming Keyboard""Logitech G13 Programmable Gameboard with LCD Display""Logitech G19 Programmable Gaming Keyboard""Logitech G35 7.1-Channel Surround Sound Headset""Logitech G430 Surround Sound Gaming Headset with Dolby 7.1 Technology""Logitech G500s Laser Gaming Mouse with Adjustable Weight Tuning""Logitech G600 MMO Gaming Mouse""Logitech G602 Wireless Gaming Mouse""Logitech G700s Rechargeable Gaming Mouse""Logitech Gaming G510s - Keyboard""Logitech Illuminated - Keyboard""Logitech Illuminated Ultrathin Keyboard with Backlighting""Logitech K350 2.4Ghz Wireless Keyboard""Logitech Keyboard K120""Logitech LS21 Speaker System - PC Multimedia - 2.1-CH - Wired""Logitech M510 Wireless Mouse""Logitech Media Keyboard K200""Logitech Mobile Speakerphone P710e - speaker phone""Logitech MX Performance Wireless Mouse""Logitech P710e Mobile Speakerphone""Logitech Trackman Marble Mouse""Logitech VX Revolution Cordless Laser Mouse for Notebooks (Black)""Logitech Wireless Anywhere Mouse MX for PC and Mac""Logitech Wireless Boombox Speaker - portable - wireless, wired""Logitech Wireless Gaming Headset G930""Logitech Wireless Headset H600 Over-The-Head Design""Logitech Wireless Headset h800""Logitech Wireless Keyboard K340""Logitech Wireless Marathon Mouse M705""Logitech Wireless Performance Mouse MX for PC and Mac""Logitech Wireless Touch Keyboard K400""Logitech Z-906 Speaker sys - home theater - 5.1-CH""Luxo Adjustable Task Clamp Lamp""Luxo Economy Swing Arm Lamp""Luxo Professional Combination Clamp-On Lamps""Luxo Professional Fluorescent Magnifier Lamp with Clamp-Mount Base""Luxo Professional Magnifying Clamp-On Fluorescent Lamps""Martin Yale Chadless Opener Electric Letter Opener""Martin-Yale Premier Letter Opener""Master Caster Door Stop, Brown""Master Caster Door Stop, Gray""Master Caster Door Stop, Large Brown""Master Caster Door Stop, Large Neon Orange""Maxell 4.7GB DVD-R""Maxell 4.7GB DVD-R 5/Pack""Maxell 4.7GB DVD-RW 3/Pack""Maxell 4.7GB DVD+R 5/Pack""Maxell 4.7GB DVD+RW 3/Pack""Maxell 74 Minute CD-R Spindle, 50/Pack""Maxell 74 Minute CDR, 10/Pack""Maxell CD-R Discs""Maxell DVD-RAM Discs""Maxell iVDR EX 500GB Cartridge""Maxell LTO Ultrium - 800 GB""Maxell Pro 80 Minute CD-R, 10/Pack""Memorex 25GB 6X Branded Blu-Ray Recordable Disc, 15/Pack""Memorex 25GB 6X Branded Blu-Ray Recordable Disc, 30/Pack""Memorex Froggy Flash Drive 4 GB""Memorex Froggy Flash Drive 8 GB""Memorex Micro Travel Drive 16 GB""Memorex Micro Travel Drive 32 GB""Memorex Micro Travel Drive 4 GB""Memorex Micro Travel Drive 8 GB""Memorex Mini Travel Drive 16 GB USB 2.0 Flash Drive""Memorex Mini Travel Drive 32 GB USB 2.0 Flash Drive""Memorex Mini Travel Drive 4 GB USB 2.0 Flash Drive""Memorex Mini Travel Drive 64 GB USB 2.0 Flash Drive""Memorex Mini Travel Drive 8 GB USB 2.0 Flash Drive""Message Book, Phone, Wirebound Standard Line Memo, 2 3/4\" X 5\"""Message Book, Standard Line \"While You Were Out\", 5 1/2\" X 4\", 200 Sets/Book""Message Book, Wirebound, Four 5 1/2\" X 4\" Forms/Pg., 200 Dupl. Sets/Book""Micro Innovations USB RF Wireless Keyboard with Mouse""Micro Innovations Wireless Classic Keyboard with Mouse""Microsoft Arc Touch Mouse""Microsoft Natural Ergonomic Keyboard 4000""Microsoft Natural Keyboard Elite""Microsoft Sculpt Comfort Mouse""Microsoft Wireless Mobile Mouse 4000""Mitel 5320 IP Phone VoIP phone""Mitel MiVoice 5330e IP Phone""Motorla HX550 Universal Bluetooth Headset""Motorola Droid Maxx""Motorola HK250 Universal Bluetooth Headset""Motorola L703CM""Motorola L804""Motorola Moto X""NETGEAR AC1750 Dual Band Gigabit Smart WiFi Router""NETGEAR N750 Dual Band Wi-Fi Gigabit Router""NETGEAR RangeMax WNR1000 Wireless Router""Newell 3-Hole Punched Plastic Slotted Magazine Holders for Binders""Newell 307""Newell 308""Newell 309""Newell 31""Newell 310""Newell 311""Newell 312""Newell 313""Newell 314""Newell 315""Newell 316""Newell 317""Newell 318""Newell 319""Newell 32""Newell 320""Newell 321""Newell 322""Newell 323""Newell 324""Newell 325""Newell 326""Newell 327""Newell 328""Newell 329""Newell 33""Newell 330""Newell 331""Newell 332""Newell 333""Newell 334""Newell 335""Newell 336""Newell 337""Newell 338""Newell 339""Newell 34""Newell 340""Newell 341""Newell 342""Newell 343""Newell 344""Newell 345""Newell 346""Newell 347""Newell 348""Newell 349""Newell 35""Newell 350""Newell 351""Newell Chalk Holder""Nokia Lumia 1020""Nokia Lumia 521 (T-Mobile)""Nokia Lumia 925""Nortel Business Series Terminal T7208 Digital phone""Nortel Meridian M3904 Professional Digital phone""Nortel Meridian M5316 Digital phone""Nortel Networks T7316 E Nt8 B27""Novimex Fabric Task Chair""Novimex High-Tech Fabric Mesh Task Chair""Novimex Swivel Fabric Task Chair""Novimex Turbo Task Chair""Nu-Dell Executive Frame""Nu-Dell EZ-Mount Plastic Wall Frames""Nu-Dell Float Frame 11 x 14 1/2""Nu-Dell Leatherette Frames""Nu-Dell Oak Frame""O'Sullivan 2-Door Barrister Bookcase in Odessa Pine""O'Sullivan 2-Shelf Heavy-Duty Bookcases""O'Sullivan 3-Shelf Heavy-Duty Bookcases""O'Sullivan 4-Shelf Bookcase in Odessa Pine""O'Sullivan 5-Shelf Heavy-Duty Bookcases""O'Sullivan Cherrywood Estates Traditional Barrister Bookcase""O'Sullivan Cherrywood Estates Traditional Bookcase""O'Sullivan Elevations Bookcase, Cherry Finish""O'Sullivan Living Dimensions 2-Shelf Bookcases""O'Sullivan Living Dimensions 3-Shelf Bookcases""O'Sullivan Living Dimensions 5-Shelf Bookcases""O'Sullivan Manor Hill 2-Door Library in Brianna Oak""O'Sullivan Plantations 2-Door Library in Landvery Oak""Office Impressions End Table, 20-1/2\"H x 24\"W x 20\"D""Office Impressions Heavy Duty Welded Shelving & Multimedia Storage Drawers""Office Star - Contemporary Swivel Chair with Padded Adjustable Arms and Flex Back""Office Star - Contemporary Task Swivel Chair""Office Star - Contemporary Task Swivel chair with 2-way adjustable arms, Plum""Office Star - Contemporary Task Swivel chair with Loop Arms, Charcoal""Office Star - Ergonomic Mid Back Chair with 2-Way Adjustable Arms""Office Star - Ergonomically Designed Knee Chair""Office Star - Mesh Screen back chair with Vinyl seat""Office Star - Mid Back Dual function Ergonomic High Back Chair with 2-Way Adjustable Arms""Office Star - Professional Matrix Back Chair with 2-to-1 Synchro Tilt and Mesh Fabric Seat""Office Star - Task Chair with Contemporary Loop Arms""Office Star Flex Back Scooter Chair with Aluminum Finish Frame""Office Star Flex Back Scooter Chair with White Frame""Binder Clips by OIC""OIC Binder Clips, Mini, 1/4\" Capacity, Black""OIC Stacking Trays""OIC Thumb-Tacks""Translucent Push Pins by OIC""Okidata B400 Printer""Okidata B401 Printer""Okidata C331dn Printer""Okidata C610n Printer""Okidata CX3535-CX4545 Multifunction Printer""Okidata MB471w Multifunction Printer""Okidata MB491 Multifunction Printer""Okidata MB760 Printer""Okidata MC362w All-in-One Printer""\"While you Were Out\" Message Book, One Form per Page""\#10 Gummed Flap White Envelopes, 100/Box""\#10 Self-Seal White Envelopes""\#10 White Business Envelopes,4 1/8 x 9 1/2""\#10- 4 1/8\" x 9 1/2\" Recycled Envelopes""\#10- 4 1/8\" x 9 1/2\" Security-Tint Envelopes""\#10-4 1/8\" x 9 1/2\" Premium Diagonal Seam Envelopes""\#6 3/4 Gummed Flap White Envelopes""1.7 Cubic Foot Compact \"Cube\" Office Refrigerators""1/4 Fold Party Design Invitations & White Envelopes, 24 8-1/2\" X 11\" Cards, 25 Env./Pack""12 Colored Short Pencils""12-1/2 Diameter Round Wall Clock""14-7/8 x 11 Blue Bar Computer Printout Paper""2300 Heavy-Duty Transfer File Systems by Perma""24 Capacity Maxi Data Binder Racks, Pearl""24-Hour Round Wall Clock""3.6 Cubic Foot Counter Height Office Refrigerator""36X48 HARDFLOOR CHAIRMAT""4009 Highlighters""4009 Highlighters by Sanford""50 Colored Long Pencils""6\" Cubicle Wall Clock, Black""9-3/4 Diameter Round Wall Clock""Aastra 57i VoIP phone""Aastra 6757i CT Wireless VoIP phone""Acrylic Self-Standing Desk Frames""Adjustable Depth Letter/Legal Cart""Adjustable Personal File Tote""Adtran 1202752G1""Airmail Envelopes""Alphabetical Labels for Top Tab Filing""Aluminum Document Frame""Aluminum Screw Posts""AmazonBasics 3-Button USB Wired Mouse""American Pencil""Ames Color-File Green Diamond Border X-ray Mailers""Anderson Hickey Conga Table Tops & Accessories""APC 7 Outlet Network SurgeArrest Surge Protector""ARKON Windshield Dashboard Air Vent Car Mount Holder""Artistic Insta-Plaque""Assorted Color Push Pins""Astroparche Fine Business Paper""Avoid Verbal Orders Carbonless Minifold Book""Bady BDG101FRU Card Printer""Bagged Rubber Bands""Barrel Sharpener""Binder Posts""Binding Machine Supplies""Black & Decker Filter for Double Action Dustbuster Cordless Vac BLDV7210""Black Print Carbonless 8 1/2\" x 8 1/4\" Rapid Memo Book""Black Print Carbonless Snap-Off Rapid Letter, 8 1/2\" x 7\"""BlackBerry Q10""Blackstonian Pencils""Blue Parrot B250XT Professional Grade Wireless Bluetooth Headset with""Blue String-Tie & Button Interoffice Envelopes, 10 x 13""BlueLounge Milo Smartphone Stand, White/Metallic""Bose SoundLink Bluetooth Speaker""BoxOffice By Design Rectangular and Half-Moon Meeting Room Tables""BPI Conference Tables""Bravo II Megaboss 12-Amp Hard Body Upright, Replacement Belts, 2 Belts per Pack""Brites Rubber Bands, 1 1/2 oz. Box""Brown Kraft Recycled Envelopes""Bush Westfield Collection Bookcases, Dark Cherry Finish, Fully Assembled""Bush Westfield Collection Bookcases, Fully Assembled""Cameo Buff Policy Envelopes""Canvas Sectional Post Binders""Career Cubicle Clock, 8 1/4\", Black""Case Logic 2.4GHz Wireless Keyboard""Catalog Binders with Expanding Posts""Cherry 142-key Programmable Keyboard""Clarity 53712""Classic Ivory Antique Telephone ZL1810""Clear Mylar Reinforcing Strips""Col-Erase Pencils with Erasers""Color-Coded Legal Exhibit Labels""Colored Envelopes""Colored Push Pins""Coloredge Poster Frame""Colorific Watercolor Pencils""Commercial WindTunnel Clean Air Upright Vacuum, Replacement Belts, Filtration Bags""Compact Automatic Electric Letter Opener""Companion Letter/Legal File, Black""Computer Printout Index Tabs""Computer Printout Paper with Letter-Trim Fine Perforations""Computer Printout Paper with Letter-Trim Perforations""Computer Room Manger, 14\"""Conquest 14 Commercial Heavy-Duty Upright Vacuum, Collection System, Accessory Kit""Contemporary Borderless Frame""Contemporary Wood/Metal Frame""Contico 72\"H Heavy-Duty Storage System""Contract Clock, 14\", Brown""Convenience Packs of Business Envelopes""Crate-A-Files""Cush Cases Heavy Duty Rugged Cover Case for Samsung Galaxy S5 - Purple""Cyber Acoustics AC-202b Speech Recognition Stereo Headset""DataProducts Ampli Magnifier Task Lamp, Black,""Dell Slim USB Multimedia Keyboard""Deluxe Chalkboard Eraser Cleaner""Deluxe Heavy-Duty Vinyl Round Ring Binder""Deluxe Rollaway Locking File with Drawer""Design Ebony Sketching Pencil""Desktop 3-Pocket Hot File""Dexim XPower Skin Super-Thin Power Case for iPhone 5 - Black""Digium D40 VoIP phone""Disposable Triple-Filter Dust Bags""Document Clip Frames""Dot Matrix Printer Tape Reel Labels, White, 5000/Box""Dual Level, Single-Width Filing Carts""Durable Pressboard Binders""DYMO CardScan Personal V9 Business Card Scanner""Eaton Premium Continuous-Feed Paper, 25\% Cotton, Letter Size, White, 1000 Shts/Box""Eberhard Faber 3 1/2\" Golf Pencils""Economy \#2 Pencils""Economy Binders""Economy Rollaway Files""EcoTones Memo Sheets""Elite 5\" Scissors""Embossed Ink Jet Note Cards""Faber Castell Col-Erase Pencils""Fashion Color Clasp Envelopes""File Shuttle I and Handi-File""File Shuttle II and Handi-File, Black""Filing/Storage Totes and Swivel Casters""Flat Face Poster Frame""Flexible Leather- Look Classic Collection Ring Binder""Floodlight Indoor Halogen Bulbs, 1 Bulb per Pack, 60 Watts""Fluorescent Highlighters by Dixon""Fujitsu fi-5015C Sheetfed Scanner""GE 30522EE2""Gear Head AU3700S Headset""Geemarc AmpliPOWER60""Geographics Note Cards, Blank, White, 8 1/2\" x 11\"""Google Nexus 5""Great White Multi-Use Recycled Paper (20Lb. and 84 Bright)""Green Bar Computer Printout Paper""Green Canvas Binder for 8-1/2\" x 14\" Sheets""Grip Seal Envelopes""GuestStacker Chair with Chrome Finish Legs""Hand-Finished Solid Wood Document Frame""Hanging Personal Folder File""Harbour Creations 67200 Series Stacking Chairs""Harbour Creations Steel Folding Chair""Heavy-Duty E-Z-D Binders""High Speed Automatic Electric Letter Opener""High-Back Leather Manager's Chair""Holmes Harmony HEPA Air Purifier for 17 x 20 Room""Home/Office Personal File Carts""Hot File 7-Pocket, Floor Stand""Hypercom P1300 Pinpad""I Need's 3d Hello Kitty Hybrid Silicone Case Cover for HTC One X 4g with 3d Hello Kitty Stylus Pen Green/pink""I.R.I.S IRISCard Anywhere 5 Card Scanner""i.Sound Portable Power - 8000 mAh""IBM Multi-Purpose Copy Paper, 8 1/2 x 11\", Case""Ideal Clamps""iHome FM Clock Radio with Lightning Dock""iKross Bluetooth Portable Keyboard + Cell Phone Stand Holder + Brush for Apple iPhone 5S 5C 5, 4S 4""Imation 8GB Mini TravelDrive USB 2.0 Flash Drive""Important Message Pads, 50 4-1/4 x 5-1/2 Forms per Pad""Ink Jet Note and Greeting Cards, 8-1/2\" x 5-1/2\" Card Size""Innergie mMini Combo Duo USB Travel Charging Kit""Insertable Tab Indexes For Data Binders""Insertable Tab Post Binder Dividers""Inter-Office Recycled Envelopes, Brown Kraft, Button-String,10\" x 13\" , 100/Box""invisibleSHIELD by ZAGG Smudge-Free Screen Protector""It's Hot Message Books with Stickers, 2 3/4\" x 5\"""Jackery Bar Premium Fast-charging Portable Charger""JBL Micro Wireless Portable Bluetooth Speaker""Jensen SMPS-640 - speaker phone""Jet-Pak Recycled Peel 'N' Seal Padded Mailers""Jiffy Padded Mailers with Self-Seal Closure""JM Magazine Binder""KLD Oscar II Style Snap-on Ultra Thin Side Flip Synthetic Leather Cover Case for HTC One HTC M7""Kleencut Forged Office Shears by Acme United Corporation""Konftel 250 Conference phone - Charcoal black""Konica Minolta magicolor 1690MF Multifunction Printer""Laminate Occasional Tables""Large Capacity Hanging Post Binders""Laser & Ink Jet Business Envelopes""Leather Task Chair, Black""Lenovo 17-Key USB Numeric Keypad""Letter or Legal Size Expandable Poly String Tie Envelopes""Letter Size Cart""Letter Size File""Letter Slitter""Letter/Legal File Tote with Clear Snap-On Lid, Black Granite""Lexmark MX611dhe Monochrome Laser Printer""LF Elite 3D Dazzle Designer Hard Case Cover, Lf Stylus Pen and Wiper For Apple Iphone 5c Mini Lite""LG Exalt""Lifetime Advantage Folding Chairs, 4/Carton""Lock-Up Easel 'Spel-Binder'""Longer-Life Soft White Bulbs""Loose Memo Sheets""Lumber Crayons""Lunatik TT5L-002 Taktik Strike Impact Protection System for iPhone 5""Macally Suction Cup Mount""Magna Visual Magnetic Picture Hangers""Magnifier Swing Arm Lamp""Manco Dry-Lighter Erasable Highlighter""Manila Recycled Extra-Heavyweight Clasp Envelopes, 6\" x 9\"""Master Big Foot Doorstop, Beige""Master Giant Foot Doorstop, Safety Yellow""Mead 1st Gear 2\" Zipper Binder, Asst. Colors""Mediabridge Sport Armband iPhone 5s""Memo Book, 100 Message Capacity, 5 3/8” x 11”""Metal Folding Chairs, Beige, 4/Carton""Micropad Numeric Keypads""Mini 13-1/2 Capacity Data Binder Rack, Pearl""Mobile Personal File Cube""Model L Table or Wall-Mount Pencil Sharpener""Mophie Juice Pack Helium for iPhone""Multi-Use Personal File Cart and Caster Set, Three Stacking Bins""Multicolor Computer Printout Paper""Multimedia Mailers""Neat Ideas Personal Hanging Folder Files, Black""NeatDesk Desktop Scanner & Digital Filing System""netTALK DUO VoIP Telephone Service""Nontoxic Chalk""OIC \#2 Pencils, Medium Soft""OIC Binder Clips""OIC Bulk Pack Metal Binder Clips""OIC Colored Binder Clips, Assorted Sizes""Ooma Telo VoIP Home Phone System""Padded Folding Chairs, Black, 4/Carton""Park Ridge Embossed Executive Business Envelopes""Pastel Pink Envelopes""PayAnywhere Card Reader""Peel & Stick Add-On Corner Pockets""Peel-Off China Markers""Pencil and Crayon Sharpener""Penpower WorldCard Pro Card Scanner""Performers Binder/Pad Holder, Black""Perixx PERIBOARD-512B, Ergonomic Split Keyboard""Perma STOR-ALL Hanging File Box, 13 1/8\"W x 12 1/4\"D x 10 1/2\"H""Permanent Self-Adhesive File Folder Labels for Typewriters, 1 1/8 x 3 1/2, White""Personal Creations Ink Jet Cards and Labels""Personal File Boxes with Fold-Down Carry Handle""Personal Filing Tote with Lid, Black/Gray""Personal Folder Holder, Ebony""Petty Cash Envelope""Pizazz Global Quick File""Plastic Binding Combs""Plastic Stacking Crates & Casters""Plymouth Boxed Rubber Bands by Plymouth""PNY Rapid USB Car Charger - Black""Portable Personal File Box""Portfile Personal File Boxes""Post-it “Important Message” Note Pad, Neon Colors, 50 Sheets/Pad""PowerGen Dual USB Car Charger""Premier Automatic Letter Opener""Premium Transparent Presentation Covers by GBC""Premium Transparent Presentation Covers, No Pattern/Clear, 8 1/2\" x 11\"""Premium Writing Pencils, Soft, \#2 by Central Association for the Blind""Presstex Flexible Ring Binders""Prestige Round Ring Binders""Prismacolor Color Pencil Set""Project Tote Personal File""PureGear Roll-On Screen Protector""Quality Park Security Envelopes""QVS USB Car Charger 2-Port 2.1Amp for iPod/iPhone/iPad/iPad 2/iPad 3""Recycled Data-Pak for Archival Bound Computer Printouts, 12-1/2 x 12-1/2 x 16""Recycled Desk Saver Line \"While You Were Out\" Book, 5 1/2\" X 4\"""Recycled Easel Ring Binders""Recycled Eldon Regeneration Jumbo File""Recycled Interoffice Envelopes with Re-Use-A-Seal Closure, 10 x 13""Recycled Interoffice Envelopes with String and Button Closure, 10 x 13""Recycled Premium Regency Composition Covers""Recycled Pressboard Report Cover with Reinforced Top Hinge""Recycled Steel Personal File for Hanging File Folders""Recycled Steel Personal File for Standard File Folders""Redi-Strip \#10 Envelopes, 4 1/8 x 9 1/2""Regeneration Desk Collection""Revere Boxed Rubber Bands by Revere""Ricoh - Ink Collector Unit for GX3000 Series Printers""Riverleaf Stik-Withit Designer Note Cubes""Rosewill 107 Normal Keys USB Wired Standard Keyboard""Round Ring Binders""Round Specialty Laser Printer Labels""RSVP Cards & Envelopes, Blank White, 8-1/2\" X 11\", 24 Cards/25 Envelopes/Set""Rubber Band Ball""Rubbermaid ClusterMat Chairmats, Mat Size- 66\" x 60\", Lip 20\" x 11\" -90 Degree Angle""Sabrent 4-Port USB 2.0 Hub""Sanitaire Vibra Groomer IR Commercial Upright Vacuum, Replacement Belts""Sannysis Cute Owl Design Soft Skin Case Cover for Samsung Galaxy S4""Satellite Sectional Post Binders""Security-Tint Envelopes""Seidio BD2-HK3IPH5-BK DILEX Case and Holster Combo for Apple iPhone 5/5s - Black""Self-Adhesive Address Labels for Typewriters with Dispenser Box""Self-Adhesive Removable Labels""Self-Adhesive Ring Binder Labels""Sensible Storage WireTech Storage Systems""Serrated Blade or Curved Handle Hand Letter Openers""Shocksock Galaxy S4 Armband""ShoreTel ShorePhone IP 230 VoIP phone""Sima Universal USB Charger""SimpliFile Personal File, Black Granite, 15w x 6-15/16d x 11-1/4h""Situations Contoured Folding Chairs, 4/Set""SKILCRAFT Telephone Shoulder Rest, 2\" x 6.5\" x 2.5\", Black""SlimView Poly Binder, 3/8\"""SmartStand Mobile Device Holder, Assorted Colors""Snap-A-Way Black Print Carbonless Ruled Speed Letter, Triplicate""Snap-A-Way Black Print Carbonless Speed Message, No Reply Area, Duplicate""Sortfiler Multipurpose Personal File Organizer, Black""Speck Products Candyshell Flip Case""Speediset Carbonless Redi-Letter 7\" x 8 1/2\"""Spigen Samsung Galaxy S5 Case Wallet""SpineVue Locking Slant-D Ring Binders by Cardinal""Square Ring Data Binders, Rigid 75 Pt. Covers, 11\" x 14-7/8\"""Stackable Trays""Stacking Tray, Side-Loading, Legal, Smoke""Stacking Trays by OIC""Staples""Star Micronics TSP100 TSP143LAN Receipt Printer""Star Micronics TSP800 TSP847IIU Receipt Printer""StarTech.com 10/100 VDSL2 Ethernet Extender Kit""Steel Personal Filing/Posting Tote""Stiletto Hand Letter Openers""Stride Job 150 Highlighters, Chisel Tip, Assorted Colors""Stur-D-Stor Shelving, Vertical 5-Shelf: 72\"H x 36\"W x 18 1/2\"D""Super Bands, 12/Pack""Super Decoflex Portable Personal File""Surelock Post Binders""Swingline SM12-08 MicroCut Jam Free Shredder""Telephone Message Books with Fax/Mobile Section, 4 1/4\" x 6\"""Telephone Message Books with Fax/Mobile Section, 5 1/2\" x 3 3/16\"""Telescoping Adjustable Floor Lamp""Tops Green Bar Computer Printout Paper""Toshiba IPT2010-SD IP Telephone""Trav-L-File Heavy-Duty Shuttle II, Black""TRENDnet 56K USB 2.0 Phone, Internet and Fax Modem""Trimflex Flexible Post Binders""Tuf-Vin Binders""Tuff Stuff Recycled Round Ring Binders""Turquoise Lead Holder with Pocket Clip""UniKeep View Case Binders""Unpadded Memo Slips""V7 USB Numeric Keypad""VariCap6 Expandable Binder""Vinyl Coated Wire Paper Clips in Organizer Box, 800/Box""Vinyl Sectional Post Binders""Vtech AT&T CL2940 Corded Speakerphone, Black""Vtech CS6719""VTech DS6151""Wausau Papers Astrobrights Colored Envelopes""Weyerhaeuser First Choice Laser/Copy Paper (20Lb. and 88 Bright)""While You Were Out Pads, 50 per Pad, 4 x 5 1/4, Green Cycle""White Business Envelopes with Contemporary Seam, Recycled White Business Envelopes""White Computer Printout Paper by Universal""White Dual Perf Computer Printout Paper, 2700 Sheets, 1 Part, Heavyweight, 20 lbs., 14 7/8 x 11""White Envelopes, White Envelopes with Clear Poly Window""White GlueTop Scratch Pads""Wi-Ex zBoost YX540 Cellular Phone Signal Booster""Wilson Electronics DB Pro Signal Booster""Wilson SignalBoost 841262 DB PRO Amplifier Kit""Wireless Extenders zBoost YX545 SOHO Signal Booster""Woodgrain Magazine Files by Perma""X-Rack File for Hanging Folders""Xblue XB-1670-86 X16 Small Office Telephone - Titanium""Xiaomi Mi3""Zipper Ring Binder Pockets""OtterBox Commuter Series Case - iPhone 5 & 5s""OtterBox Commuter Series Case - Samsung Galaxy S4""OtterBox Defender Series Case - iPhone 5c""OtterBox Defender Series Case - Samsung Galaxy S4""Panasonic Business Telephones KX-T7736""Panasonic KP-150 Electric Pencil Sharpener""Panasonic KP-310 Heavy-Duty Electric Pencil Sharpener""Panasonic KP-350BK Electric Pencil Sharpener with Auto Stop""Panasonic KP-380BK Classic Electric Pencil Sharpener""Panasonic KP-4ABK Battery-Operated Pencil Sharpener""Panasonic KX - TS880B Telephone""Panasonic KX MB2000 Monochrome Laser All-in-One Printer""Panasonic KX MB2030 Monochrome Laser All-in-One Printer""Panasonic KX MB2061 Multifunction Printer""Panasonic KX MB3020 Highspeed Multifunction Printer""Panasonic KX MC6040 Color Laser Multifunction Printer""Panasonic KX T7731-B Digital phone""Panasonic KX T7736-B Digital phone""Panasonic KX TS208W Corded phone""Panasonic KX TS3282B Corded phone""Panasonic KX TS3282W Corded phone""Panasonic KX-TG6512B DECT 6.0 Plus Digital 2-Handset Cordless Phone""Panasonic KX-TG6844B Expandable Digital Cordless Telephone""Panasonic KX-TG9471B""Panasonic KX-TG9541B DECT 6.0 Digital 2-Line Expandable Cordless Phone With Digital Answering System""Panasonic Kx-TS550""Peel & Seel Envelopes""Peel & Seel Recycled Catalog Envelopes, Brown""Plantronics 81402""Plantronics Audio 478 Stereo USB Headset""Plantronics Audio 995 Wireless Stereo Headset""Plantronics Calisto P620-M USB Wireless Speakerphone System""Plantronics Cordless Phone Headset with In-line Volume - M214C""Plantronics CS 50-USB - headset - Convertible, Monaural""Plantronics CS510 - Over-the-Head monaural Wireless Headset System""Plantronics Encore H101 Dual Earpieces Headset""Plantronics HL10 Handset Lifter""Plantronics MX500i Earset""Plantronics S12 Corded Telephone Headset System""Plantronics Savi W720 Multi-Device Wireless Headset System""Plantronics Single Ear Headset""Plantronics Voyager Pro HD - Bluetooth Headset""Plantronics Voyager Pro Legend""Poly Designer Cover & Back""Poly String Tie Envelopes""Polycom CX300 Desktop Phone USB VoIP phone""Polycom CX600 IP Phone VoIP phone""Polycom SoundPoint IP 450 VoIP phone""Polycom SoundPoint Pro SE-225 Corded phone""Polycom SoundStation2 EX Conference phone""Polycom VoiceStation 500 Conference phone""Polycom VVX 310 VoIP phone""Prang Colored Pencils""Prang Drawing Pencil Set""Prang Dustless Chalk Sticks""Premier Electric Letter Opener""Premier Elliptical Ring Binder, Black""Pressboard Covers with Storage Hooks, 9 1/2\" x 11\", Light Blue""Pressboard Data Binder, Crimson, 12\" X 8 1/2\"""Pressboard Data Binders by Wilson Jones""Pressboard Hanging Data Binders for Unburst Sheets""Pyle PMP37LED""Pyle PRT45 Retro Home Telephone""Quartet Alpha White Chalk, 12/Pack""Quartet Omega Colored Chalk, 12/Pack""Razer Kraken 7.1 Surround Sound Over Ear USB Gaming Headset""Razer Kraken PRO Over Ear PC and Music Headset""Razer Tiamat Over Ear 7.1 Surround Sound PC Gaming Headset""RCA 25214 2-Line Corded Telephone""RCA H5401RE1 DECT 6.0 4-Line Cordless Handset With Caller ID/Call Waiting""RCA ViSYS 25423RE1 Corded phone""RCA ViSYS 25425RE1 Corded phone""RCA ViSYS 25825 Wireless digital phone""RCA Visys Integrated PBX 8-Line Router""REDIFORM Incoming/Outgoing Call Register, 11\" X 8 1/2\", 100 Messages""Rediform S.O.S. 1-Up Phone Message Bk, 4-1/4x3-1/16 Bk, 1 Form/Pg, 40 Messages/Bk, 3/Pk""Rediform S.O.S. Phone Message Books""Rediform Voice Mail Log Books""Rediform Wirebound \"Phone Memo\" Message Book, 11 x 5-3/4""Riverside Furniture Oval Coffee Table, Oval End Table, End Table with Drawer""Riverside Furniture Stanwyck Manor Table Series""Riverside Palais Royal Lawyers Bookcase, Royale Cherry Finish""Rogers Deluxe File Chest""Rogers Handheld Barrel Pencil Sharpener""Rogers Jumbo File, Granite""Rogers Profile Extra Capacity Storage Tub""Rush Hierlooms Collection 1\" Thick Stackable Bookcases""Rush Hierlooms Collection Rich Wood Bookcases""SAFCO Arco Folding Chair""SAFCO Boltless Steel Shelving""Safco Chair Connectors, 6/Carton""Safco Commercial Shelving""SAFCO Commercial Wire Shelving, 72h""SAFCO Commercial Wire Shelving, Black""Safco Contoured Stacking Chairs""Safco Drafting Table""SAFCO Folding Chair Trolley""Safco Industrial Shelving""Safco Industrial Wire Shelving""Safco Industrial Wire Shelving System""SAFCO Mobile Desk Side File, Wire Frame""SAFCO Optional Arm Kit for Workspace Cribbage Stacking Chair""SAFCO PlanMaster Boards, 60w x 37-1/2d, White Melamine""SAFCO PlanMaster Heigh-Adjustable Drafting Table Base, 43w x 30d x 30-37h, Black""Safco Steel Mobile File Cart""Safco Value Mate Series Steel Bookcases, Baked Enamel Finish on Steel, Gray""Safco Value Mate Steel Bookcase, Baked Enamel Finish on Steel, Black""Safco Wire Cube Shelving System, For Use as 4 or 5 14\" Cubes, Black""Samsung Convoy 3""Samsung Galaxy Mega 6.3""Samsung Galaxy Note 2""Samsung Galaxy Note 3""Samsung Galaxy S III - 16GB - pebble blue (T-Mobile)""Samsung Galaxy S4""Samsung Galaxy S4 Active""Samsung Galaxy S4 Mini""Samsung HM1900 Bluetooth Headset""Samsung Replacement EH64AVFWE Premium Headset""Samsung Rugby III""SanDisk Cruzer 16 GB USB Flash Drive""SanDisk Cruzer 32 GB USB Flash Drive""SanDisk Cruzer 4 GB USB Flash Drive""SanDisk Cruzer 64 GB USB Flash Drive""SanDisk Cruzer 8 GB USB Flash Drive""SanDisk Ultra 16 GB MicroSDHC Class 10 Memory Card""SanDisk Ultra 32 GB MicroSDHC Class 10 Memory Card""SanDisk Ultra 64 GB MicroSDHC Class 10 Memory Card""Sanford 52201 APSCO Electric Pencil Sharpener""Sanford Colorific Colored Pencils, 12/Box""Sanford Colorific Eraseable Coloring Pencils, 12 Count""Sanford Colorific Scented Colored Pencils, 12/Pack""Sanford EarthWrite Recycled Pencils, Medium Soft, \#2""Sanford Liquid Accent Highlighters""SANFORD Liquid Accent Tank-Style Highlighters""SANFORD Major Accent Highlighters""Sanford Pocket Accent Highlighters""Sanford Prismacolor Professional Thick Lead Art Pencils, 36-Color Set""Sanford Uni-Blazer View Highlighters, Chisel Tip, Yellow""Sanyo 2.5 Cubic Foot Mid-Size Office Refrigerators""Sanyo Counter Height Refrigerator with Crisper, 3.6 Cubic Foot, Stainless Steel/Black""Sauder Barrister Bookcases""Sauder Camden County Barrister Bookcase, Planked Cherry Finish""Sauder Camden County Collection Libraries, Planked Cherry Finish""Sauder Camden County Collection Library""Sauder Cornerstone Collection Library""Sauder Facets Collection Library, Sky Alder Finish""Sauder Facets Collection Locker/File Cabinet, Sky Alder Finish""Sauder Forest Hills Library with Doors, Woodland Oak Finish""Sauder Forest Hills Library, Woodland Oak Finish""Sauder Inglewood Library Bookcases""Sauder Mission Library with Doors, Fruitwood Finish""Seth Thomas 12\" Clock w/ Goldtone Case""Seth Thomas 13 1/2\" Wall Clock""Seth Thomas 14\" Day/Date Wall Clock""Seth Thomas 14\" Putty-Colored Wall Clock""Seth Thomas 16\" Steel Case Clock""Seth Thomas 8 1/2\" Cubicle Clock""Sharp 1540cs Digital Laser Copier""Sharp AL-1530CS Digital Copier""Smead Adjustable Mobile File Trolley with Lockable Top""Smead Alpha-Z Color-Coded Name Labels First Letter Starter Set""Smead Alpha-Z Color-Coded Second Alphabetical Labels and Starter Set""Socket Bluetooth Cordless Hand Scanner (CHS)""Sony 16GB Class 10 Micro SDHC R40 Memory Card""Sony 32GB Class 10 Micro SDHC R40 Memory Card""Sony 64GB Class 10 Micro SDHC R40 Memory Card""Sony 8GB Class 10 Micro SDHC R40 Memory Card""Sony Micro Vault Click 16 GB USB 2.0 Flash Drive""Sony Micro Vault Click 4 GB USB 2.0 Flash Drive""Sony Micro Vault Click 8 GB USB 2.0 Flash Drive""Southworth 100\% Cotton The Best Paper""Southworth 100\% Résumé Paper, 24lb.""Southworth 25\% Cotton Antique Laid Paper & Envelopes""Southworth 25\% Cotton Granite Paper & Envelopes""Southworth 25\% Cotton Linen-Finish Paper & Envelopes""Southworth 25\% Cotton Premium Laser Paper and Envelopes""Southworth Parchment Paper & Envelopes""Southworth Structures Collection""Space Solutions Commercial Steel Shelving""Space Solutions HD Industrial Steel Shelving.""Space Solutions Industrial Galvanized Steel Shelving.""Square Credit Card Reader""Square Credit Card Reader, 4 1/2\" x 4 1/2\" x 1\", White""Standard Line “While You Were Out” Hardbound Telephone Message Book""Standard Rollaway File with Lock""Stanley Bostitch Contemporary Electric Pencil Sharpeners""Stanley Contemporary Battery Pencil Sharpeners""Sterilite Officeware Hinged File Box""Sterilite Show Offs Storage Containers""Stockwell Gold Paper Clips""Stockwell Push Pins""Storex Dura Pro Binders""Storex DuraTech Recycled Plastic Frosted Binders""Storex Flexible Poly Binders with Double Pockets""Strathmore \#10 Envelopes, Ultimate White""Strathmore Photo Frame Cards""Strathmore Photo Mount Cards""Tenex \"The Solids\" Textured Chair Mats""Tenex 46\" x 60\" Computer Anti-Static Chairmat, Rectangular Shaped""Tenex Antistatic Computer Chair Mats""Tenex B1-RE Series Chair Mats for Low Pile Carpets""Tenex Carpeted, Granite-Look or Clear Contemporary Contour Shape Chair Mats""Tenex Chairmat w/ Average Lip, 45\" x 53\"""Tenex Chairmats For Use With Carpeted Floors""Tenex Chairmats For Use with Hard Floors""Tenex Contemporary Contur Chairmats for Low and Medium Pile Carpet, Computer, 39\" x 49\"""Tenex File Box, Personal Filing Tote with Lid, Black""Tenex Personal Filing Tote With Secure Closure Lid, Black/Frost""Tenex Personal Project File with Scoop Front Design, Black""Tenex Personal Self-Stacking Standard File Box, Black/Gray""Tenex Traditional Chairmats for Hard Floors, Average Lip, 36\" x 48\"""Tenex Traditional Chairmats for Medium Pile Carpet, Standard Lip, 36\" x 48\"""Tenex V2T-RE Standard Weight Series Chair Mat, 45\" x 53\", Lip 25\" x 12\"""Tennsco 16-Compartment Lockers with Coat Rack""Tennsco 6- and 18-Compartment Lockers""Tennsco Commercial Shelving""Tennsco Double-Tier Lockers""Tennsco Industrial Shelving""Tennsco Lockers, Gray""Tennsco Lockers, Sand""Tennsco Regal Shelving Units""Tennsco Single-Tier Lockers""Tennsco Snap-Together Open Shelving Units, Starter Sets and Add-On Units""Tennsco Stur-D-Stor Boltless Shelving, 5 Shelves, 24\" Deep, Sand""Tensor \"Hersey Kiss\" Styled Floor Lamp""Tensor Brushed Steel Torchiere Floor Lamp""Tensor Computer Mounted Lamp""Tensor Track Tree Floor Lamp""Texas Instrument TI-15 Fraction Calculator""Texas Instrument TI-30a Scientific Calculator""Texas Instrument TI-30X Scientific Calculator""Texas Instrument TI-30X Solar Scientific Calculator""Texas Instrument TI-36X Solar Scientific Calculator""Texas Instruments TI-34 Scientific Calculator""Things To Do Today Pad""Things To Do Today Spiral Book""TOPS \"Important Message\" Pads, Canary, 4-1/4 x 5-1/2, 50 Sheets per Pad""TOPS 4 x 6 Fluorescent Color Memo Sheets, 500 Sheets per Pack""TOPS Carbonless Receipt Book, Four 2-3/4 x 7-1/4 Money Receipts per Page""TOPS Money Receipt Book, Consecutively Numbered in Red,""TOPS Voice Message Log Book, Flash Format""Tops White Computer Printout Paper""Tops Wirebound Message Log Books""Tripp Lite Isotel 6 Outlet Surge Protector with Fax/Modem Protection""Tripp Lite Isotel 8 Ultra 8 Outlet Metal Surge""Tripp Lite TLP810NET Broadband Surge for Modem/Fax""Tyvek Top-Opening Peel & Seel Envelopes, Gray""Tyvek Top-Opening Peel & Seel Envelopes, Plain White""Tyvek Interoffice Envelopes, 9 1/2\" x 12 1/2\", 100/Box""Tyvek Side-Opening Peel & Seel Expanding Envelopes""Ultra Commercial Grade Dual Valve Door Closer""Ultra Door Kickplate, 8\"H x 34\"W""Ultra Door Pull Handle""Ultra Door Push Plate""Permanent Self-Adhesive File Folder Labels for Typewriters by Universal""Self-Adhesive Address Labels for Typewriters by Universal""Universal Premium White Copier/Laser Paper (20Lb. and 87 Bright)""Universal Recycled Hanging Pressboard Report Binders, Letter Size""Universal Ultra Bright White Copier/Laser Paper, 8 1/2\" x 11\", Ream""Verbatim 25 GB 6x Blu-ray Single Layer Recordable Disc, 1/Pack""Verbatim 25 GB 6x Blu-ray Single Layer Recordable Disc, 10/Pack""Verbatim 25 GB 6x Blu-ray Single Layer Recordable Disc, 25/Pack""Verbatim 25 GB 6x Blu-ray Single Layer Recordable Disc, 3/Pack""Verbatim Slim CD and DVD Storage Cases, 50/Pack""Wasp CCD Handheld Bar Code Reader""Wasp WCS 3905 CCD Barcode Scanner""WD My Passport Ultra 1TB Portable External Hard Drive""WD My Passport Ultra 2TB Portable External Hard Drive""WD My Passport Ultra 500GB Portable External Hard Drive""Westinghouse Clip-On Gooseneck Lamps""Westinghouse Floor Lamp with Metal Mesh Shade, Black""Westinghouse Mesh Shade Clip-On Gooseneck Lamp, Black""Wilson Jones “Snap” Scratch Pad Binder Tool for Ring Binders""Wilson Jones 1\" Hanging DublLock Ring Binders""Wilson Jones 14 Line Acrylic Coated Pressboard Data Binders""Wilson Jones Active Use Binders""Wilson Jones Century Plastic Molded Ring Binders""Wilson Jones Clip & Carry Folder Binder Tool for Ring Binders, Clear""Wilson Jones Custom Binder Spines & Labels""Wilson Jones data.warehouse D-Ring Binders with DublLock""Wilson Jones DublLock D-Ring Binders""Wilson Jones Easy Flow II Sheet Lifters""Wilson Jones Elliptical Ring 3 1/2\" Capacity Binders, 800 sheets""Wilson Jones Four-Pocket Poly Binders""Wilson Jones Hanging Recycled Pressboard Data Binders""Wilson Jones Hanging View Binder, White, 1\"""Wilson Jones Heavy-Duty Casebound Ring Binders with Metal Hinges""Wilson Jones Impact Binders""Wilson Jones International Size A4 Ring Binders""Wilson Jones Leather-Like Binders with DublLock Round Rings""Wilson Jones Ledger-Size, Piano-Hinge Binder, 2\", Blue""Wilson Jones Legal Size Ring Binders""Wilson Jones Standard D-Ring Binders""Wilson Jones Suede Grain Vinyl Binders""Wilson Jones Turn Tabs Binder Tool for Ring Binders""Wirebound Four 2-3/4 x 5 Forms per Page, 400 Sets per Book""Wirebound Message Book, 4 per Page""Wirebound Message Books, 2 7/8\" x 5\", 3 Forms per Page""Wirebound Message Books, 5-1/2 x 4 Forms, 2 or 4 Forms per Page""Wirebound Message Books, Four 2 3/4 x 5 Forms per Page, 200 Sets per Book""Wirebound Message Books, Four 2 3/4 x 5 White Forms per Page""Wirebound Message Books, Four 2 3/4\" x 5\" Forms per Page, 600 Sets per Book""Wirebound Message Books, Two 4 1/4\" x 5\" Forms per Page""Wirebound Message Forms, Four 2 3/4 x 5 Forms per Page, Pink Paper""Wirebound Service Call Books, 5 1/2\" x 4\"""Wirebound Voice Message Log Book""Xerox 188""Xerox 1880""Xerox 1881""Xerox 1882""Xerox 1883""Xerox 1884""Xerox 1885""Xerox 1886""Xerox 1887""Xerox 1888""Xerox 1889""Xerox 189""Xerox 1890""Xerox 1891""Xerox 1892""Xerox 1893""Xerox 1894""Xerox 1895""Xerox 1896""Xerox 1897""Xerox 1898""Xerox 1899""Xerox 19""Xerox 190""Xerox 1900""Xerox 1901""Xerox 1902""Xerox 1903""Xerox 1904""Xerox 1905""Xerox 1906""Xerox 1907""Xerox 1908""Xerox 1909""Xerox 191""Xerox 1910""Xerox 1911""Xerox 1912""Xerox 1913""Xerox 1914""Xerox 1915""Xerox 1916""Xerox 1917""Xerox 1918""Xerox 1919""Xerox 192""Xerox 1920""Xerox 1921""Xerox 1922""Xerox 1923""Xerox 1924""Xerox 1925""Xerox 1926""Xerox 1927""Xerox 1928""Xerox 1929""Xerox 193""Xerox 1930""Xerox 1931""Xerox 1932""Xerox 1933""Xerox 1934""Xerox 1935""Xerox 1936""Xerox 1937""Xerox 1938""Xerox 1939""Xerox 194""Xerox 1940""Xerox 1941""Xerox 1942""Xerox 1943""Xerox 1944""Xerox 1945""Xerox 1946""Xerox 1947""Xerox 1948""Xerox 1949""Xerox 195""Xerox 1950""Xerox 1951""Xerox 1952""Xerox 1953""Xerox 1954""Xerox 1955""Xerox 1956""Xerox 1957""Xerox 1958""Xerox 1959""Xerox 196""Xerox 1960""Xerox 1961""Xerox 1962""Xerox 1963""Xerox 1964""Xerox 1965""Xerox 1966""Xerox 1967""Xerox 1968""Xerox 1969""Xerox 197""Xerox 1970""Xerox 1972""Xerox 1973""Xerox 1974""Xerox 1975""Xerox 1976""Xerox 1977""Xerox 1978""Xerox 1979""Xerox 198""Xerox 1980""Xerox 1981""Xerox 1982""Xerox 1983""Xerox 1984""Xerox 1985""Xerox 1986""Xerox 1987""Xerox 1988""Xerox 1989""Xerox 199""Xerox 1990""Xerox 1991""Xerox 1992""Xerox 1993""Xerox 1994""Xerox 1995""Xerox 1996""Xerox 1997""Xerox 1998""Xerox 1999""Xerox 2""Xerox 20""Xerox 200""Xerox 2000""Xerox 201""Xerox 202""Xerox 203""Xerox 204""Xerox 205""Xerox 206""Xerox 207""Xerox 208""Xerox 209""Xerox 21""Xerox 210""Xerox 211""Xerox 212""Xerox 213""Xerox 214""Xerox 215""Xerox 216""Xerox 217""Xerox 218""Xerox 219""Xerox 22""Xerox 220""Xerox 221""Xerox 222""Xerox 223""Xerox 224""Xerox 225""Xerox 226""Xerox 227""Xerox 228""Xerox 229""Xerox 23""Xerox 230""Xerox 231""Xerox 232""Xerox 4200 Series MultiUse Premium Copy Paper (20Lb. and 84 Bright)""Xerox Blank Computer Paper""Xerox Color Copier Paper, 11\" x 17\", Ream""Xerox WorkCentre 6505DN Laser Multifunction Printer""XtraLife ClearVue Slant-D Ring Binder, White, 3\"""XtraLife ClearVue Slant-D Ring Binders by Cardinal""Zebra GK420t Direct Thermal/Thermal Transfer Printer""Zebra GX420t Direct Thermal/Thermal Transfer Printer""Zebra Zazzle Fluorescent Highlighters""Zebra ZM400 Thermal Label Printer"
<_.fcp.ObjectModelTableType.true...column caption='Orders' datatype='table' name='[__tableau_internal_object_id__].[Orders_ECFCA1FB690A41FE803BC071773BA862]' role='measure' type='quantitative' />
<_.fcp.ObjectModelTableType.true...column caption='People' datatype='table' name='[__tableau_internal_object_id__].[People_D73023733B004CC1B3CB1ACF62F4A965]' role='measure' type='quantitative' />
<_.fcp.ObjectModelTableType.true...column caption='Returns' datatype='table' name='[__tableau_internal_object_id__].[Returns_2AA0FE4D737A4F63970131D0E7480A03]' role='measure' type='quantitative' />
[Country/Region][Region][State][City][Postal Code][Category][Sub-Category][Product Name (group)][Product Name]
<_.fcp.ObjectModelEncapsulateLegacy.true...object-graph>
[Sample - Superstore].[none:Category:nk]
[Sample - Superstore].[none:Category:nk][Sample - Superstore].[none:Segment:nk][Sample - Superstore].[none:Sub-Category:nk]
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
gGVTAcvmD5YpbPKOzTAfAAAAAElFTkSuQmCC
================================================
FILE: test/assets/unicode.tds
================================================
a130[a][xy]a1stringCount255true"SQL_WVARCHAR""SQL_C_WCHAR""true"Today's Date130[Today's Date][xy]a1stringCount255true"SQL_WVARCHAR""SQL_C_WCHAR""true"x3[x][xy]x2integerSum10true"SQL_INTEGER""SQL_C_SLONG"y3[y][xy]y3integerSum10true"SQL_INTEGER""SQL_C_SLONG"año
Something will go here too, in a muted gray
================================================
FILE: test/bvt.py
================================================
import os
import unittest
from lxml import etree as ET
from test.assets.index import *
from tableaudocumentapi import Workbook, Datasource, Connection, ConnectionParser
from tableaudocumentapi.xfile import TableauInvalidFileException, TableauVersionNotSupportedException
class ConnectionParserTests(unittest.TestCase):
def test_can_extract_legacy_connection(self):
parser = ConnectionParser(ET.parse(TABLEAU_93_TDS), '9.2')
connections = parser.get_connections()
self.assertIsInstance(connections, list)
self.assertIsInstance(connections[0], Connection)
self.assertEqual(connections[0].dbname, 'TestV1')
def test_can_extract_federated_connections(self):
parser = ConnectionParser(ET.parse(TABLEAU_10_TDS), '10.0')
connections = parser.get_connections()
self.assertIsInstance(connections, list)
self.assertIsInstance(connections[0], Connection)
self.assertEqual(connections[0].dbname, 'TestV1')
class ConnectionModelTests(unittest.TestCase):
def setUp(self):
self.connection = ET.parse(TABLEAU_CONNECTION_XML).getroot()
def test_can_read_attributes_from_connection(self):
conn = Connection(self.connection)
self.assertEqual(conn.dbname, 'TestV1')
self.assertEqual(conn.username, '')
self.assertEqual(conn.server, 'mssql2012')
self.assertEqual(conn.dbclass, 'sqlserver')
self.assertEqual(conn.authentication, 'sspi')
self.assertEqual(conn.port, '1433')
self.assertEqual(conn.initial_sql, '')
self.assertEqual(conn.query_band, '')
def test_can_write_attributes_to_connection(self):
conn = Connection(self.connection)
conn.dbname = 'BubblesInMyDrink'
conn.server = 'mssql2014'
conn.username = 'bob'
conn.port = '1337'
conn.initial_sql = "insert values (1, 'winning') into schema.table"
conn.query_band = 'TableauReport='
self.assertEqual(conn.dbname, 'BubblesInMyDrink')
self.assertEqual(conn.username, 'bob')
self.assertEqual(conn.server, 'mssql2014')
self.assertEqual(conn.port, '1337')
self.assertEqual(conn.initial_sql, "insert values (1, 'winning') into schema.table")
self.assertEqual(conn.query_band, 'TableauReport=')
def test_can_delete_port_from_connection(self):
conn = Connection(self.connection)
conn.port = None
self.assertEqual(conn.port, None)
self.assertIsNone(conn._connectionXML.get('port'))
def test_can_delete_initial_sql_from_connection(self):
conn = Connection(self.connection)
conn.initial_sql = None
self.assertEqual(conn.initial_sql, None)
self.assertIsNone(conn._connectionXML.get('initial_sql'))
def test_can_delete_query_band_from_connection(self):
conn = Connection(self.connection)
conn.query_band = None
self.assertEqual(conn.query_band, None)
self.assertIsNone(conn._connectionXML.get('query_band'))
def test_bad_dbclass_rasies_attribute_error(self):
conn = Connection(self.connection)
conn.dbclass = 'sqlserver'
self.assertEqual(conn.dbclass, 'sqlserver')
with self.assertRaises(AttributeError):
conn.dbclass = 'NotReal'
def test_can_create_connection_from_scratch(self):
conn = Connection.from_attributes(
server='a', dbname='b', username='c', dbclass='mysql', authentication='d')
self.assertEqual(conn.server, 'a')
self.assertEqual(conn.dbname, 'b')
self.assertEqual(conn.username, 'c')
self.assertEqual(conn.dbclass, 'mysql')
self.assertEqual(conn.authentication, 'd')
def test_can_create_oracle_connection_from_scratch(self):
conn = Connection.from_attributes(
server='a', dbname='b', username='c', dbclass='oracle', schema='d', service='e')
self.assertEqual(conn.server, 'a')
self.assertEqual(conn.schema, 'd')
self.assertEqual(conn.service, 'e')
def test_can_create_datasource_from_connections(self):
conn1 = Connection.from_attributes(
server='a', dbname='b', username='c', dbclass='mysql', authentication='d')
conn2 = Connection.from_attributes(
server='1', dbname='2', username='3', dbclass='mysql', port='1337', authentication='7')
ds = Datasource.from_connections('test', connections=[conn1, conn2])
self.assertEqual(ds.connections[0].server, 'a')
self.assertEqual(ds.connections[0].port, None)
self.assertEqual(ds.connections[1].server, '1')
self.assertEqual(ds.connections[1].port, '1337')
class ConnectionParserInComplicatedWorkbooks(unittest.TestCase):
def setUp(self):
with open(MULTI_CONNECTION_10, 'rb') as in_file, open('test.twb', 'wb') as out_file:
out_file.write(in_file.read())
self.twb_file = out_file
def tearDown(self):
self.twb_file.close()
os.unlink(self.twb_file.name)
def test_can_mixed_connections_workbook(self):
wb = Workbook(self.twb_file.name)
self.assertTrue(len(wb.datasources), 2)
self.assertTrue(len(wb.datasources[1].connections), 2)
self.assertEqual(wb.datasources[0].connections[0].dbclass, 'sqlproxy')
self.assertEqual(wb.datasources[1].connections[0].dbclass, 'mysql')
self.assertEqual(wb.datasources[1].connections[1].dbclass, 'sqlserver')
class DatasourceModelTests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_93_TDS, 'rb') as in_file, open('test.tds', 'wb') as out_file:
out_file.write(in_file.read())
self.tds_file = out_file
def tearDown(self):
self.tds_file.close()
os.unlink(self.tds_file.name)
def test_can_extract_datasource_from_file(self):
ds = Datasource.from_file(self.tds_file.name)
self.assertEqual(ds.name, 'sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo')
self.assertEqual(ds.version, '9.3')
def test_can_extract_connection(self):
ds = Datasource.from_file(self.tds_file.name)
self.assertIsInstance(ds.connections[0], Connection)
self.assertIsInstance(ds.connections, list)
def test_can_save_tds(self):
original_tds = Datasource.from_file(self.tds_file.name)
original_tds.connections[0].dbname = 'newdb'
original_tds.save()
new_tds = Datasource.from_file(self.tds_file.name)
self.assertEqual(new_tds.connections[0].dbname, 'newdb')
def test_save_has_xml_declaration(self):
original_tds = Datasource.from_file(self.tds_file.name)
original_tds.connections[0].dbname = 'newdb'
original_tds.save()
with open(self.tds_file.name) as f:
first_line = f.readline().strip() # first line should be xml tag
self.assertEqual(
first_line, "")
class DatasourceModelV10Tests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_10_TDS, 'rb') as in_file, open('test.twb', 'wb') as out_file:
out_file.write(in_file.read())
self.tds_file = out_file
def tearDown(self):
self.tds_file.close()
os.unlink(self.tds_file.name)
def test_can_extract_datasource_from_file(self):
ds = Datasource.from_file(self.tds_file.name)
self.assertEqual(ds.name, 'federated.1s4nxn20cywkdv13ql0yk0g1mpdx')
self.assertEqual(ds.version, '10.0')
def test_can_extract_connection(self):
ds = Datasource.from_file(self.tds_file.name)
self.assertIsInstance(ds.connections[0], Connection)
self.assertIsInstance(ds.connections, list)
def test_can_save_tds(self):
original_tds = Datasource.from_file(self.tds_file.name)
original_tds.connections[0].dbname = 'newdb'
original_tds.save()
new_tds = Datasource.from_file(self.tds_file.name)
self.assertEqual(new_tds.connections[0].dbname, 'newdb')
def test_can_save_as_tds(self):
new_filename = os.path.join(
os.path.dirname(self.tds_file.name),
"new_{}".format(os.path.basename(self.tds_file.name))
)
try:
original_tds = Datasource.from_file(self.tds_file.name)
original_tds.connections[0].dbname = 'newdb'
original_tds.save_as(new_filename)
new_tds = Datasource.from_file(new_filename)
self.assertEqual(new_tds.connections[0].dbname, 'newdb')
finally:
if os.path.exists(new_filename):
os.unlink(new_filename)
class DatasourceModelV10TDSXTests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_10_TDSX, 'rb') as in_file, open('test.tdsx', 'wb') as out_file:
out_file.write(in_file.read())
self.tdsx_file = out_file
def tearDown(self):
self.tdsx_file.close()
os.unlink(self.tdsx_file.name)
def test_can_open_tdsx(self):
ds = Datasource.from_file(self.tdsx_file.name)
self.assertTrue(ds.connections)
self.assertTrue(ds.name)
def test_can_open_tdsx_and_save_changes(self):
original_tdsx = Datasource.from_file(self.tdsx_file.name)
original_tdsx.connections[0].server = 'newdb'
original_tdsx.save()
new_tdsx = Datasource.from_file(self.tdsx_file.name)
self.assertEqual(new_tdsx.connections[
0].server, 'newdb')
def test_can_open_tdsx_and_save_as_changes(self):
new_tdsx_filename = 'newtdsx.tdsx'
original_wb = Datasource.from_file(self.tdsx_file.name)
original_wb.connections[0].server = 'newdb'
original_wb.save_as(new_tdsx_filename)
new_wb = Datasource.from_file(new_tdsx_filename)
self.assertEqual(new_wb.connections[
0].server, 'newdb')
os.unlink(new_tdsx_filename)
class WorkbookModelTests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_93_TWB, 'rb') as in_file, open('test.twb', 'wb') as out_file:
out_file.write(in_file.read())
self.workbook_file = out_file
def tearDown(self):
self.workbook_file.close()
os.unlink(self.workbook_file.name)
def test_can_extract_datasource(self):
wb = Workbook(self.workbook_file.name)
self.assertEqual(len(wb.datasources), 1)
self.assertIsInstance(wb.datasources[0], Datasource)
self.assertEqual(wb.datasources[0].name,
'sqlserver.17u3bqc16tjtxn14e2hxh19tyvpo')
def test_can_get_worksheets(self):
wb = Workbook(self.workbook_file.name)
self.assertIsNotNone(wb.worksheets)
def test_has_filename(self):
wb = Workbook(self.workbook_file.name)
self.assertEqual(wb.filename, self.workbook_file.name)
def test_can_update_datasource_connection_and_save(self):
original_wb = Workbook(self.workbook_file.name)
original_wb.datasources[0].connections[0].dbname = 'newdb'
original_wb.save()
new_wb = Workbook(self.workbook_file.name)
self.assertEqual(new_wb.datasources[0].connections[
0].dbname, 'newdb')
class WorkbookModelV10Tests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_10_TWB, 'rb') as in_file, open('test.twb', 'wb') as out_file:
out_file.write(in_file.read())
self.workbook_file = out_file
def tearDown(self):
self.workbook_file.close()
os.unlink(self.workbook_file.name)
def test_can_extract_datasourceV10(self):
wb = Workbook(self.workbook_file.name)
self.assertEqual(len(wb.datasources), 1)
self.assertEqual(len(wb.datasources[0].connections), 2)
self.assertIsInstance(wb.datasources[0].connections, list)
self.assertIsInstance(wb.datasources[0], Datasource)
self.assertEqual(wb.datasources[0].name,
'federated.1s4nxn20cywkdv13ql0yk0g1mpdx')
def test_can_update_datasource_connection_and_saveV10(self):
original_wb = Workbook(self.workbook_file.name)
original_wb.datasources[0].connections[0].dbname = 'newdb'
original_wb.save()
new_wb = Workbook(self.workbook_file.name)
self.assertEqual(new_wb.datasources[0].connections[
0].dbname, 'newdb')
def test_save_has_xml_declaration(self):
original_wb = Workbook(self.workbook_file.name)
original_wb.datasources[0].connections[0].dbname = 'newdb'
original_wb.save()
with open(self.workbook_file.name) as f:
first_line = f.readline().strip() # first line should be xml tag
self.assertEqual(
first_line, "")
class WorkbookModelV10TWBXTests(unittest.TestCase):
def setUp(self):
with open(TABLEAU_10_TWBX, 'rb') as in_file, open('test.twbx', 'wb') as out_file:
out_file.write(in_file.read())
self.workbook_file = out_file
def tearDown(self):
self.workbook_file.close()
os.unlink(self.workbook_file.name)
def test_can_open_twbx(self):
wb = Workbook(self.workbook_file.name)
self.assertTrue(wb.datasources)
self.assertTrue(wb.datasources[0].connections)
def test_can_open_twbx_and_save_changes(self):
original_wb = Workbook(self.workbook_file.name)
original_wb.datasources[0].connections[0].server = 'newdb'
original_wb.save()
new_wb = Workbook(self.workbook_file.name)
self.assertEqual(new_wb.datasources[0].connections[
0].server, 'newdb')
def test_can_open_twbx_and_save_as_changes(self):
new_twbx_filename = 'newtwbx.twbx'
original_wb = Workbook(self.workbook_file.name)
original_wb.datasources[0].connections[0].server = 'newdb'
original_wb.save_as(new_twbx_filename)
new_wb = Workbook(new_twbx_filename)
self.assertEqual(new_wb.datasources[0].connections[
0].server, 'newdb')
os.unlink(new_twbx_filename)
class EmptyWorkbookWillLoad(unittest.TestCase):
def test_no_exceptions_thrown(self):
wb = Workbook(EMPTY_WORKBOOK)
self.assertIsNotNone(wb)
class LoadOnlyValidFileTypes(unittest.TestCase):
def test_exception_when_workbook_given_tdsx(self):
with self.assertRaises(TableauInvalidFileException):
wb = Workbook(TABLEAU_10_TDSX)
def test_exception_when_datasource_given_twbx(self):
with self.assertRaises(TableauInvalidFileException):
ds = Datasource.from_file(TABLEAU_10_TWBX)
class SupportedWorkbookVersions(unittest.TestCase):
def test_82_workbook_throws_exception(self):
with self.assertRaises(TableauVersionNotSupportedException):
wb = Workbook(TABLEAU_82_TWB)
if __name__ == '__main__':
unittest.main()
================================================
FILE: test/test_datasource.py
================================================
import os
import os.path
import shutil
import tempfile
import unittest
from tableaudocumentapi import Datasource, Workbook
TEST_ASSET_DIR = os.path.join(
os.path.dirname(__file__),
'assets'
)
TEST_TDS_FILE = os.path.join(
TEST_ASSET_DIR,
'datasource_test.tds'
)
TEST_TWB_FILE = os.path.join(
TEST_ASSET_DIR,
'datasource_test.twb'
)
class DataSourceFieldsTDS(unittest.TestCase):
def setUp(self):
self.ds = Datasource.from_file(TEST_TDS_FILE)
self.to_delete = set()
def cleanUp(self):
for path in self.to_delete:
if os.path.isdir(path):
shutil.rmtree(path, ignore_errors=True)
elif os.path.isfile(path):
os.unlink(path)
def get_temp_file(self, filename):
tempdir = tempfile.mkdtemp('tda-datasource')
self.to_delete.add(tempdir)
return os.path.join(tempdir, filename)
def test_datasource_returns_correct_fields(self):
self.assertIsNotNone(self.ds.fields)
self.assertIsNotNone(self.ds.fields.get('[Number of Records]', None))
def test_datasource_returns_calculation_from_fields(self):
self.assertEqual('1', self.ds.fields['[Number of Records]'].calculation)
def test_datasource_uses_metadata_record(self):
self.assertEqual('Sum', self.ds.fields['[x]'].default_aggregation)
def test_datasource_column_name_contains_apostrophy(self):
self.assertIsNotNone(self.ds.fields.get("[Today's Date]", None))
def test_datasource_field_can_get_caption(self):
self.assertEqual(self.ds.fields['[a]'].caption, 'A')
self.assertEqual(getattr(self.ds.fields['[a]'], 'caption', None), 'A')
def test_datasource_field_caption_can_be_used_to_query(self):
self.assertIsNotNone(self.ds.fields.get('A', None))
def test_datasource_field_is_nominal(self):
self.assertTrue(self.ds.fields['[a]'].is_nominal)
def test_datasource_field_is_quantitative(self):
self.assertTrue(self.ds.fields['[y]'].is_quantitative)
def test_datasource_field_is_ordinal(self):
self.assertTrue(self.ds.fields['[x]'].is_ordinal)
def test_datasource_field_datatype(self):
self.assertEqual(self.ds.fields['[x]'].datatype, 'integer')
def test_datasource_field_role(self):
self.assertEqual(self.ds.fields['[x]'].role, 'measure')
def test_datasource_field_description(self):
actual = self.ds.fields['[a]'].description
self.assertIsNotNone(actual)
self.assertTrue(u'muted gray' in actual)
def test_datasource_caption(self):
actual = self.ds.caption
self.assertIsNotNone(actual)
self.assertEqual(actual, 'foo')
def test_datasource_can_set_caption(self):
filename = self.get_temp_file('test_datasource_can_set_caption')
self.ds.caption = 'bar'
self.ds.save_as(filename)
actual = Datasource.from_file(filename)
self.assertIsNotNone(actual)
self.assertIsNotNone(actual.caption)
self.assertEqual(actual.caption, 'bar')
def test_datasource_can_remove_caption(self):
filename = self.get_temp_file('test_datasource_can_remove_caption')
del self.ds.caption
self.ds.save_as(filename)
actual = Datasource.from_file(filename)
self.assertIsNotNone(actual)
self.assertEqual(actual.caption, '')
def test_datasource_clear_repository_location(self):
filename = os.path.join(TEST_ASSET_DIR, 'clear-repository-test.tds')
self.assertIsNotNone(self.ds._datasourceXML.find('.//repository-location'))
self.ds.clear_repository_location()
try:
self.ds.save_as(filename)
with open(filename, 'r') as newfile:
self.assertFalse('repository-location' in newfile.read())
finally:
if os.path.exists(filename):
os.unlink(filename)
class DataSourceFieldsTWB(unittest.TestCase):
def setUp(self):
self.wb = Workbook(TEST_TWB_FILE)
# Assume the first datasource in the file
self.ds = self.wb.datasources[0]
def test_datasource_fields_loaded_in_workbook(self):
self.assertIsNotNone(self.ds.fields)
self.assertIsNotNone(self.ds.fields.get('[Number of Records]', None))
class DataSourceFieldsFoundIn(unittest.TestCase):
def setUp(self):
self.wb = Workbook(TEST_TWB_FILE)
# Assume the first datasource in the file
self.ds = self.wb.datasources[0]
def test_datasource_fields_found_in_returns_fields(self):
actual_values = self.ds.fields.used_by_sheet('Sheet 1')
self.assertIsNotNone(actual_values)
self.assertEqual(1, len(actual_values))
self.assertIn('A', (x.name for x in actual_values))
def test_datasource_fields_found_in_does_not_return_fields_not_used_in_worksheet(self):
actual_values = self.ds.fields.used_by_sheet('Sheet 1')
self.assertIsNotNone(actual_values)
self.assertEqual(1, len(actual_values))
self.assertNotIn('X', (x.name for x in actual_values))
def test_datasource_fields_found_in_returns_multiple_fields(self):
actual_values = self.ds.fields.used_by_sheet('Sheet 2')
self.assertIsNotNone(actual_values)
self.assertEqual(2, len(actual_values))
self.assertIn('A', (x.name for x in actual_values))
self.assertIn('X', (x.name for x in actual_values))
self.assertNotIn('Y', (x.name for x in actual_values))
def test_datasource_fields_found_in_accepts_lists(self):
actual_values = self.ds.fields.used_by_sheet(['Sheet 1', 'Sheet 2'])
self.assertIsNotNone(actual_values)
self.assertEqual(2, len(actual_values))
self.assertIn('A', (x.name for x in actual_values))
self.assertIn('X', (x.name for x in actual_values))
self.assertNotIn('Y', (x.name for x in actual_values))
================================================
FILE: test/test_field.py
================================================
import unittest
import os.path
from tableaudocumentapi import Datasource, Field
from tableaudocumentapi.field import _find_metadata_record
TEST_ASSET_DIR = os.path.join(
os.path.dirname(__file__),
'assets'
)
TEST_TDS_FILE = os.path.join(
TEST_ASSET_DIR,
'datasource_test.tds'
)
TEST_UNICODE_FILE = os.path.join(
TEST_ASSET_DIR,
'unicode.tds'
)
class FieldsUnitTest(unittest.TestCase):
def test_field_throws_if_no_data_passed_in(self):
with self.assertRaises(AttributeError):
Field()
class FindMetaDataRecordEdgeTest(unittest.TestCase):
class MockXmlWithNoFind(object):
def find(self, *args, **kwargs):
return None
def test_find_metadata_record_returns_none(self):
self.assertIsNone(_find_metadata_record(self.MockXmlWithNoFind(), 'foo'))
class FieldsHandleUnicode(unittest.TestCase):
def test_description_unicode(self):
ds = Datasource.from_file(TEST_UNICODE_FILE)
self.assertIsNotNone(ds.fields['A'].description)
================================================
FILE: test/test_field_change.py
================================================
import unittest
import os.path
from tableaudocumentapi import Datasource
from lxml import etree as ET
TEST_ASSET_DIR = os.path.join(
os.path.dirname(__file__),
'assets'
)
TEST_TDS_FILE = os.path.join(
TEST_ASSET_DIR,
'field_change_test.tds'
)
TEST_TDS_FILE_OUTPUT = os.path.join(
TEST_ASSET_DIR,
'field_change_test_output.tds'
)
MESSAGES = {
'test_change_values1': 'Value has not changed when altering values for {}.',
'test_change_values2': 'XML-Structure has not changed when altering values for {}.',
'test_change_valuesFail1': 'Value has changed when submitting the wrong value for {}.',
'test_change_valuesFail2': 'XML-Structure has changed when submitting the wrong value for {}.',
'test_change_aliases1': 'XML-Structure has not changed when altering aliases for {}.',
'test_change_aliases2': 'Values have not changed when altering aliases for {}.'
}
NEW_VALUES = {
'caption': 'testcaption',
'alias': 'testalias',
'datatype': 'boolean',
'role': 'measure',
'type': 'ordinal'
}
WRONG_VALUES = {
'datatype': 'boolani',
'role': 'messhure',
'type': 'gordinol'
}
ALIASES = {
'one': 'two',
'three': 'four',
'five': 'six'
}
class TestFieldChange(unittest.TestCase):
def setUp(self):
self.tds = Datasource.from_file(TEST_TDS_FILE)
def current_hash(self):
""" Return a hash of the current state of the XML.
Allows us to easily identify whether the underlying XML-structure
of a TDS-file has actually changed. Avoids false positives if,
for example, a fields value has changed but the XML hasn't.
"""
return hash(ET.tostring(self.tds._datasourceTree.getroot()))
def check_state_change(self, should_change, msg, field_name):
""" Check whether the XML has changed and update the current state.
Args:
should_change: Whether the XML is supposed to have changed or not. Boolean.
msg: The message to be displayed in an error case, as key for the MESSAGES dict. String.
field_name: The field name that will be displayed in the error message. String.
Returns:
Nothing.
"""
new_state = self.current_hash()
compare_func = self.assertNotEqual if should_change else self.assertEqual
compare_func(
self.state,
new_state,
msg=MESSAGES[msg].format(field_name)
)
self.state = new_state
def test_change_values(self):
""" Test if the value changes of a field are reflected in the object and in the underlying XML structure.
"""
field_to_test = "[amount]"
self.state = self.current_hash()
# change all fields
for key, value in NEW_VALUES.items():
setattr(self.tds.fields[field_to_test], key, value)
# the new value must be reflected in the object
self.assertEqual(
getattr(self.tds.fields[field_to_test], key),
value,
msg=MESSAGES['test_change_values1'].format(key)
)
# the new value must be reflected in the xml
self.check_state_change(True, 'test_change_values2', key)
def test_change_values_fail(self):
""" Test if the value changes of a field are rejected if the wrong arguments are passed.
"""
field_to_test = "[amount]"
self.state = self.current_hash()
# change all fields
for key, value in WRONG_VALUES.items():
with self.assertRaises(ValueError):
# this must fail
setattr(self.tds.fields[field_to_test], key, value)
# the new value must NOT be reflected in the object
self.assertNotEqual(
getattr(self.tds.fields[field_to_test], key),
value,
msg=MESSAGES['test_change_valuesFail1'].format(key)
)
# the new value must NOT be reflected in the xml
self.check_state_change(False, 'test_change_valuesFail2', key)
def test_remove_field(self):
""" Test if a Field can be removed.
"""
field_to_test = "[amount]"
self.state = self.current_hash()
# change all fields
field = self.tds.fields["[amount]"]
self.tds.remove_field(field)
self.assertNotEqual(self.state, self.current_hash())
def test_change_aliases(self):
""" Test if the alias changes of a field are reflected in the object and in the underlying XML structure.
"""
field_to_test = "[amount]"
self.state = self.current_hash()
# change all fields
for key, value in ALIASES.items():
self.tds.fields[field_to_test].add_alias(key, value)
# the new value must be reflected in the xml
self.check_state_change(True, 'test_change_aliases1', field_to_test)
# check whether all fields of ALIASES have been applied
self.assertEqual(
set(self.tds.fields[field_to_test].aliases),
set(ALIASES),
msg=MESSAGES['test_change_aliases2'].format(field_to_test)
)
def test_calculation_base(self):
""" Test if the initial state of calculated fields is correct.
"""
# Demo data has 2 calculated fields at the start
original_len = len(self.tds.calculations)
# Can't write to calculation for not-calculated fields!
self.tds.fields['[name]'].calculation = '1 * 2'
self.assertEqual(len(self.tds.calculations), original_len + 1)
self.tds.fields['[name]'].calculation = '2 * 3'
self.assertEqual(len(self.tds.calculations), original_len + 1)
self.tds.fields['[price]'].calculation = '2 * 3'
self.assertEqual(len(self.tds.calculations), original_len + 2)
def test_calculation_change(self):
""" Test whether changing calculations of a field works.
"""
self.state = self.current_hash()
new_calc = '33 * 44'
fld_name = '[Calculation_357754699576291328]'
self.tds.calculations[fld_name].calculation = new_calc
# Check object representation
self.assertEqual(self.tds.calculations[fld_name].calculation, new_calc)
# Check XML representation
new_state = self.current_hash()
self.assertNotEqual(self.state, new_state)
def test_calculation_new(self):
""" Test if creating a new calculation works.
"""
args = 'TestCalc', '12*34', 'integer', 'measure', 'quantitative', 'False'
original_len = len(self.tds.calculations)
self.tds.add_calculation(*args)
self.assertEqual(len(self.tds.calculations), original_len + 1)
def test_calculation_remove(self):
""" Test if deleting a calculation works.
"""
args = 'TestCalc2', '12*34', 'integer', 'measure', 'quantitative', 'True'
original_len = len(self.tds.calculations)
calc = self.tds.add_calculation(*args)
self.assertEqual(len(self.tds.calculations), original_len + 1)
self.tds.remove_field(calc)
self.assertEqual(len(self.tds.calculations), original_len)
def tearDown(self):
""" Test if the file can be saved.
Output file will be ignored by git, but can be used to verify the results.
"""
self.tds.save_as(TEST_TDS_FILE_OUTPUT)
if __name__ == '__main__':
unittest.main()
================================================
FILE: test/test_multidict.py
================================================
import unittest
import os.path
import functools
from tableaudocumentapi.multilookup_dict import MultiLookupDict
class MLDTests(unittest.TestCase):
def setUp(self):
self.mld = MultiLookupDict({
'[foo]': {
'alias': 'bar',
'caption': 'baz',
'value': 1
},
'[bar]': {
'caption': 'foo',
'value': 2
},
'[baz]': {
'value': 3
}
})
def test_multilookupdict_can_be_empty(self):
mld = MultiLookupDict()
self.assertIsNotNone(mld)
def test_multilookupdict_name_only(self):
actual = self.mld['[baz]']
self.assertEqual(3, actual['value'])
def test_multilookupdict_alias_overrides_everything(self):
actual = self.mld['bar']
self.assertEqual(1, actual['value'])
def test_mutlilookupdict_caption_overrides_id(self):
actual = self.mld['foo']
self.assertEqual(2, actual['value'])
def test_mutlilookupdict_can_still_find_id_even_with_alias(self):
actual = self.mld['[foo]']
self.assertEqual(1, actual['value'])
def test_mutlilookupdict_can_still_find_caption_even_with_alias(self):
actual = self.mld['baz']
self.assertEqual(1, actual['value'])
def test_mutlilookupdict_can_still_find_id_even_with_caption(self):
actual = self.mld['[bar]']
self.assertEqual(2, actual['value'])
def test_multilookupdict_gives_key_error_on_invalid_key(self):
try:
self.mld.get('foobar')
self.fail('should have thrown key error')
except KeyError as ex:
self.assertEqual(str(ex), "'foobar'")
def test_multilookupdict_get_returns_default_value(self):
default_value = ('default', 'return', 'value')
actual = self.mld.get('foobar', default_value)
self.assertEqual(actual, default_value)
def test_multilookupdict_get_returns_value(self):
actual = self.mld.get('baz')
self.assertEqual(1, actual['value'])
def test_multilookupdict_can_set_item(self):
before = self.mld['baz']
self.mld['baz'] = 4
self.assertEqual(4, self.mld['baz'])
def test_multilookupdict_can_set_new_item(self):
self.mld['wakka'] = 1
self.assertEqual(1, self.mld['wakka'])
def test_multilookupdict_can_set_with_alias(self):
self.mld['bar'] = 2
self.assertEqual(2, self.mld['[foo]'])
================================================
FILE: test/test_workbook.py
================================================
import unittest
import os.path
from tableaudocumentapi import Datasource, Workbook
TEST_ASSET_DIR = os.path.join(
os.path.dirname(__file__),
'assets'
)
EPHEMERAL_FIELD_FILE = os.path.join(
TEST_ASSET_DIR,
'ephemeral_field.twb'
)
SHAPES_FILE = os.path.join(
TEST_ASSET_DIR,
'shapes_test.twb'
)
DASHBOARDS_FILE = os.path.join(
TEST_ASSET_DIR,
'filtering.twb'
)
class EphemeralFields(unittest.TestCase):
def test_ephemeral_fields_do_not_cause_errors(self):
wb = Workbook(EPHEMERAL_FIELD_FILE)
self.assertIsNotNone(wb)
class Shapes(unittest.TestCase):
def test_shape_exist(self):
wb = Workbook(SHAPES_FILE)
self.assertEqual(wb.shapes, ['Bug Tracking/bug.png',
'Bug Tracking/icon-scheduleitem.png',
'Bug Tracking/light.png',
'Bug Tracking/mail.png',
]
)
def test_shape_count(self):
wb = Workbook(SHAPES_FILE)
self.assertEqual(len(wb.shapes), 4)
class Dashboards(unittest.TestCase):
def test_dashboards_setup(self):
wb = Workbook(DASHBOARDS_FILE)
self.assertIsNotNone(wb)
self.assertEqual(wb.dashboards, ['setTest'])
================================================
FILE: test/test_xfile.py
================================================
from test.assets.index import *
import unittest
import zipfile
from tableaudocumentapi.xfile import find_file_in_zip
from tableaudocumentapi import Workbook, Datasource
TEST_ASSET_DIR = os.path.join(
os.path.dirname(__file__),
'assets'
)
BAD_ZIP_FILE = os.path.join(
TEST_ASSET_DIR,
'BadZip.zip'
)
TWBX_WITH_CACHE_FILES = os.path.join(
TEST_ASSET_DIR,
'Cache.twbx'
)
class XFileEdgeTests(unittest.TestCase):
def test_find_file_in_zip_no_xml_file(self):
badzip = zipfile.ZipFile(BAD_ZIP_FILE)
self.assertIsNone(find_file_in_zip(badzip))
def test_only_find_twbs(self):
twb_from_twbx_with_cache = zipfile.ZipFile(TWBX_WITH_CACHE_FILES)
self.assertEqual(find_file_in_zip(twb_from_twbx_with_cache), 'Superstore.twb')
class Namespacing(unittest.TestCase):
def assertContainsUserNamespace(self, filename):
with open(filename, 'r') as in_file:
# the namespace is in the first five lines for all the docs I've checked
lineCount = 0
doc_beginning_excerpt = ""
while lineCount < 5:
doc_beginning_excerpt += (in_file.readline().strip()) # first line should be xml tag
lineCount += 1
found = doc_beginning_excerpt.rfind("xmlns:user=")
# print(doc_beginning_excerpt[found:found+10])
self.assertRegex(doc_beginning_excerpt, "xmlns:user=")
def test_save_preserves_namespace_twb(self):
filename = COMPLEX_TWB
self.assertContainsUserNamespace(filename)
wb = Workbook(filename)
new_name = 'saved-as-twb.twb'
wb.save_as(new_name)
self.assertContainsUserNamespace(new_name)
def demo_bug_ns_not_preserved_if_not_used(self):
filename = TABLEAU_10_TDS
self.assertContainsUserNamespace(filename)
wb = Datasource.from_file(filename)
new_name = 'saved-as-tds.tds'
wb.save_as(new_name)
self.assertContainsUserNamespace(new_name)