diff --git a/.ci/36.yml b/.ci/36.yml new file mode 100644 index 00000000..b75e93cb --- /dev/null +++ b/.ci/36.yml @@ -0,0 +1,23 @@ +name: test +channels: + - conda-forge +dependencies: + - python=3.6 + - pandas + - geopandas>=0.7 + - matplotlib + - scikit-learn + - seaborn + - numpy + - scipy + - pip + - libpysal + - coveralls + - descartes + - pytest + - pytest-mpl + - pytest-cov + - twine + - tqdm + - pandana + - urbanaccess diff --git a/.ci/37.yml b/.ci/37.yml new file mode 100644 index 00000000..632cf189 --- /dev/null +++ b/.ci/37.yml @@ -0,0 +1,23 @@ +name: test +channels: + - conda-forge +dependencies: + - python=3.7 + - pandas + - geopandas>=0.7 + - matplotlib + - scikit-learn + - seaborn + - numpy + - scipy + - pip + - libpysal + - coveralls + - descartes + - pytest + - pytest-mpl + - pytest-cov + - twine + - tqdm + - pandana + - urbanaccess diff --git a/.ci/38.yml b/.ci/38.yml new file mode 100644 index 00000000..64f3e7cb --- /dev/null +++ b/.ci/38.yml @@ -0,0 +1,23 @@ +name: test +channels: + - conda-forge +dependencies: + - python=3.8 + - pandas + - geopandas>=0.7 + - matplotlib + - scikit-learn + - seaborn + - numpy + - scipy + - pip + - libpysal + - descartes + - coveralls + - pytest + - pytest-mpl + - pytest-cov + - twine + - tqdm + - pandana + - urbanaccess diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml new file mode 100644 index 00000000..39ec6a57 --- /dev/null +++ b/.github/workflows/unittests.yml @@ -0,0 +1,49 @@ + name: Unit Tests + on: + push: + branches: + - '*' + pull_request: + branches: + - '*' + + jobs: + unittests: + name: CI (${{ matrix.os }}-${{ matrix.environment-file }}) + runs-on: ${{ matrix.os }} + continue-on-error: ${{ matrix.experimental }} + timeout-minutes: 90 + strategy: + matrix: + os: ['ubuntu-latest', 'macos-latest', 'windows-latest'] + environment-file: [.ci/36.yml, .ci/37.yml, .ci/38.yml] + experimental: [false] + steps: + - uses: actions/checkout@v2 + - uses: goanpeca/setup-miniconda@v1 + with: + miniconda-version: 'latest' + auto-update-conda: true + auto-activate-base: false + environment-file: ${{ matrix.environment-file }} + activate-environment: test + - shell: bash -l {0} + run: conda info --all + - shell: bash -l {0} + run: conda list + - shell: bash -l {0} + run: conda config --show-sources + - shell: bash -l {0} + run: conda config --show + - shell: bash -l {0} + run: pip install -e . --no-deps --force-reinstall + - name: Pytest + shell: bash -l {0} + run: | + pytest -v segregation --cov=segregation --cov-report=xml + - name: codecov (${{ matrix.os }}, ${{ matrix.environment-file }}) + uses: codecov/codecov-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + file: ./coverage.xml + name: segregation-codecov \ No newline at end of file diff --git a/.github/workflows/upload_package.yml b/.github/workflows/upload_package.yml new file mode 100644 index 00000000..a2637fd5 --- /dev/null +++ b/.github/workflows/upload_package.yml @@ -0,0 +1,63 @@ + +name: Release Package + +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10 + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine jupyter urllib3 pandas pyyaml + python setup.py sdist bdist_wheel + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@master + with: + password: ${{ secrets.pypi_password }} + - name: Run Changelog + run: | + jupyter nbconvert --to notebook --execute --inplace --ExecutePreprocessor.timeout=-1 --ExecutePreprocessor.kernel_name=python3 tools/gitcount.ipynb + - name: Cat Changelog + uses: pCYSl5EDgo/cat@master + id: changetxt + with: + path: ./tools/changelog.md + env: + TEXT: ${{ steps.changetxt.outputs.text }} + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body: ${{ steps.changetxt.outputs.text }} + draft: false + prerelease: false + - name: Get Asset name + run: | + export PKG=$(ls dist/) + set -- $PKG + echo "::set-env name=whl_path::$1" + - name: Upload Release Asset + id: upload-release-asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} # This pulls from the CREATE RELEASE step above, referencing it's ID to get its outputs object, which include a `upload_url`. See this blog post for more info: https://jasonet.co/posts/new-features-of-github-actions/#passing-data-to-future-steps + asset_path: dist/${{ env.whl_path }} + asset_name: ${{ env.whl_path }} + asset_content_type: application/zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9cf56a4e..00000000 --- a/.travis.yml +++ /dev/null @@ -1,66 +0,0 @@ -language: python -dist: xenial -sudo: true -branches: -only: - - master - -python: - - 3.6 - - 3.7 -env: - - PYSAL_PYPI=true - - PYSAL_PYPI=false - -matrix: - allow_failures: - - python: 3.6 - env: PYSAL_PYPI=false - - python: 3.7 - env: PYSAL_PYPI=false - -before_install: - - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh - - chmod +x miniconda.sh - - ./miniconda.sh -b -p ./miniconda - - export PATH=`pwd`/miniconda/bin:$PATH - - conda update --yes conda - - conda config --add channels conda-forge - - conda config --add channels udst - - conda config --set channel_priority strict - - conda create -y -q -n test-env python=$TRAVIS_PYTHON_VERSION - - source activate test-env - -install: - - conda install --yes pip nose - - conda install --yes -c conda-forge geopandas #comment this line if geopandas is not a dependency for the package - - conda install --yes --file requirements.txt; - - pip install -r requirements_tests.txt; - - which pip - - if "$PYSAL_PYPI"; then - echo 'testing pypi libpysal'; - else - echo 'testing git libpysal'; - git clone https://github.com/pysal/libpysal.git; - cd libpysal; pip install .; cd ../; - fi; - - -script: - - pwd - - ls -al - - python setup.py sdist >/dev/null - - python setup.py install - - nosetests -v segregation --with-coverage - -notifications: - email: - recipients: - - renanxcortes+travis@gmail.com - - sjsrey+travis@gmail.com - - knaaptime+travis@gmail.com - on_change: always - on_failure: always - -after_success: - - coveralls diff --git a/doc/generated/segregation.network.calc_access.rst b/doc/generated/segregation.network.calc_access.rst deleted file mode 100644 index 3ad04b4d..00000000 --- a/doc/generated/segregation.network.calc_access.rst +++ /dev/null @@ -1,6 +0,0 @@ -segregation.network.calc_access -============================== - -.. currentmodule:: segregation.network - -.. autofunction:: calc_access diff --git a/doc/generated/segregation.network.get_network.rst b/doc/generated/segregation.network.get_network.rst deleted file mode 100644 index 7687c7bd..00000000 --- a/doc/generated/segregation.network.get_network.rst +++ /dev/null @@ -1,6 +0,0 @@ -segregation.network.get_osm_network -============================== - -.. currentmodule:: segregation.network - -.. autofunction:: get_osm_network diff --git a/doc/generated/segregation.spatial.SpatialInformationTheory.rst b/doc/generated/segregation.spatial.SpatialInformationTheory.rst deleted file mode 100644 index bfe1eac2..00000000 --- a/doc/generated/segregation.spatial.SpatialInformationTheory.rst +++ /dev/null @@ -1,16 +0,0 @@ -segregation.spatial.SpatialInformationTheory -============================================= - -.. currentmodule:: segregation.spatial - -.. autoclass:: SpatialInformationTheory - - - .. automethod:: __init__ - - - .. rubric:: Methods - - .. autosummary:: - - ~SpatialInformationTheory.__init__ diff --git a/doc/generated/segregation.spatial.compute_segregation_profile.rst b/doc/generated/segregation.spatial.compute_segregation_profile.rst deleted file mode 100644 index 5fa4d17c..00000000 --- a/doc/generated/segregation.spatial.compute_segregation_profile.rst +++ /dev/null @@ -1,6 +0,0 @@ -segregation.spatial.compute_segregation_profile -================================================ - -.. currentmodule:: segregation.spatial - -.. autofunction:: compute_segregation_profile diff --git a/docs/.buildinfo b/docs/.buildinfo new file mode 100644 index 00000000..e3fbbb98 --- /dev/null +++ b/docs/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: 1abb69093b22996e21358efdfe7002eb +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/_modules/index.html b/docs/_modules/index.html new file mode 100644 index 00000000..c42574b0 --- /dev/null +++ b/docs/_modules/index.html @@ -0,0 +1,146 @@ + + + + + + + Overview: module code — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/aspatial/aspatial_indexes.html b/docs/_modules/segregation/aspatial/aspatial_indexes.html new file mode 100644 index 00000000..3e14a478 --- /dev/null +++ b/docs/_modules/segregation/aspatial/aspatial_indexes.html @@ -0,0 +1,2167 @@ + + + + + + + segregation.aspatial.aspatial_indexes — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.aspatial.aspatial_indexes

+"""
+Aspatial based Segregation Metrics
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu>, Sergio J. Rey <sergio.rey@ucr.edu> and Elijah Knaap <elijah.knaap@ucr.edu>"
+
+import numpy as np
+import pandas as pd
+import warnings
+import geopandas as gpd
+
+from scipy.stats import norm
+from scipy.optimize import minimize
+
+from segregation.util.util import _dep_message, DeprecationHelper, _nan_handle
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = ['Dissim', 
+           
+           'Gini_Seg',
+           'GiniSeg',
+           
+           'Entropy', 
+           'Isolation',
+           'Exposure',
+           'Atkinson',
+           
+           'Correlation_R',
+           'CorrelationR',
+           
+           'Con_Prof',
+           'ConProf',
+           
+           'Modified_Dissim',
+           'ModifiedDissim',
+           
+           'Modified_Gini_Seg',
+           'ModifiedGiniSeg',
+           
+           'Bias_Corrected_Dissim',
+           'BiasCorrectedDissim',
+           
+           'Density_Corrected_Dissim',
+           'DensityCorrectedDissim',
+           
+           'MinMax']
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+
+
+def _min_max(data, group_pop_var, total_pop_var):
+    """
+    Calculation of the Aspatial version of SpatialMinMax
+
+    Parameters
+    ----------
+
+    data          : a pandas DataFrame
+    
+    group_pop_var : string
+                    The name of variable in data that contains the population size of the group of interest
+                    
+    total_pop_var : string
+                    The name of variable in data that contains the total population of the unit
+
+    Returns
+    ----------
+
+    statistic : float
+                MinMax Index
+                
+    core_data : a pandas DataFrame
+                A pandas DataFrame that contains the columns used to perform the estimate.
+
+    Notes
+    -----
+    Based on O'Sullivan & Wong (2007). A Surfaceâ€Based Approach to Measuring Spatial Segregation.
+    Geographical Analysis 39 (2). https://doi.org/10.1111/j.1538-4632.2007.00699.x
+
+    Reference: :cite:`osullivanwong2007surface`.
+    
+    We'd like to thank @AnttiHaerkoenen for this contribution!
+    
+    """
+    
+    if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)):
+        raise TypeError('group_pop_var and total_pop_var must be strings')
+    
+    if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)):    
+        raise ValueError('group_pop_var and total_pop_var must be variables of data')
+        
+    data = data.rename(columns={group_pop_var: 'group_pop_var', 
+                                total_pop_var: 'total_pop_var'})
+    
+    if any(data.total_pop_var < data.group_pop_var):    
+        raise ValueError('Group of interest population must equal or lower than the total population of the units.')
+   
+    data['group_2_pop_var'] = data['total_pop_var'] - data['group_pop_var']
+    
+    data['group_1_pop_var_norm'] = data['group_pop_var'] / data['group_pop_var'].sum()
+    data['group_2_pop_var_norm'] = data['group_2_pop_var'] / data['group_2_pop_var'].sum()
+    
+    density_1 = data['group_1_pop_var_norm'].values
+    density_2 = data['group_2_pop_var_norm'].values
+    densities = np.vstack([
+        density_1,
+        density_2
+    ])
+    v_union = densities.max(axis=0).sum()
+    v_intersect = densities.min(axis=0).sum()
+    
+    MM = 1 - v_intersect / v_union
+    
+    if not isinstance(data, gpd.GeoDataFrame):
+        core_data = data[['group_pop_var', 'total_pop_var']]
+    
+    else:    
+        core_data = data[['group_pop_var', 'total_pop_var', 'geometry']]
+    
+    return MM, core_data
+
+
+
[docs]class MinMax: + """ + Calculation of the Aspatial version of SpatialMinMax + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + MinMax Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on O'Sullivan & Wong (2007). A Surfaceâ€Based Approach to Measuring Spatial Segregation. + Geographical Analysis 39 (2). https://doi.org/10.1111/j.1538-4632.2007.00699.x + + Reference: :cite:`osullivanwong2007surface`. + + We'd like to thank @AnttiHaerkoenen for this contribution! + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _min_max(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _min_max
+ + + + + +def _dissim(data, group_pop_var, total_pop_var): + """ + Calculation of Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Dissimilarity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + T = t.sum() + P = x.sum() / T + + # If a unit has zero population, the group of interest frequency is zero + pi = np.where(t == 0, 0, x / t) + + D = (((t * abs(pi - P)))/ (2 * T * P * (1 - P))).sum() + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return D, core_data + + +
[docs]class Dissim: + """ + Classic Dissimilarity Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Dissimilarity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the degree of dissimilarity (D) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import Dissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> dissim_index = Dissim(df, 'tractid', 'pop10') + >>> dissim_index.statistic + 0.31565682496226544 + + The interpretation of this value is that 31.57% of the non-hispanic black population would have to move to reach eveness in the Riverside County. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _dissim(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _dissim
+ + + +def _gini_seg(data, group_pop_var, total_pop_var): + """ + Calculation of Gini Segregation index + + Parameters + ---------- + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + statistic : float + Gini Segregation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + if any(data.total_pop_var < data.group_pop_var): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + T = data.total_pop_var.sum() + P = data.group_pop_var.sum() / T + + # If a unit has zero population, the group of interest frequency is zero + data = data.assign(ti = data.total_pop_var, + pi = np.where(data.total_pop_var == 0, 0, data.group_pop_var/data.total_pop_var)) + + num = (np.matmul(np.array(data.ti)[np.newaxis].T, np.array(data.ti)[np.newaxis]) * abs(np.array(data.pi)[np.newaxis].T - np.array(data.pi)[np.newaxis])).sum() + den = (2 * T**2 * P * (1-P)) + G = num / den + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return G, core_data + + +
[docs]class GiniSeg: + """ + Classic Gini Segregation Index + + Parameters + ---------- + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + Attributes + ---------- + statistic : float + Gini Segregation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Gini Segregation Index (G) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import GiniSeg + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> gini_seg_index = GiniSeg(df, 'tractid', 'pop10') + >>> gini_seg_index.statistic + 0.44620350030600087 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _gini_seg(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _gini_seg
+ + + +def _entropy(data, group_pop_var, total_pop_var): + """ + Calculation of Entropy index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Entropy Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + T = t.sum() + P = x.sum() / T + + # If a unit has zero population, the group of interest frequency is zero + pi = np.where(t == 0, 0, x / t) + + E = P * np.log(1 / P) + (1 - P) * np.log(1 / (1 - P)) + Ei = pi * np.log(1 / pi) + (1 - pi) * np.log(1 / (1 - pi)) + H = np.nansum(t * (E - Ei) / (E * T)) # If some pi is zero, numpy will treat as zero + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return H, core_data + + +
[docs]class Entropy: + """ + Classic Entropy Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Entropy Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Entropy (H) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import Entropy + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> entropy_index = Entropy(df, 'tractid', 'pop10') + >>> entropy_index.statistic + 0.08636489348167173 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _entropy(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _entropy
+ + + + +def _isolation(data, group_pop_var, total_pop_var): + """ + Calculation of Isolation index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Isolation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + The group of interest is labelled as group X. + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + X = x.sum() + xPx = np.nansum((x / X) * (x / t)) + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return xPx, core_data + + +
[docs]class Isolation: + """ + Classic Isolation Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Isolation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Isolation Index (xPx) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import Isolation + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> isolation_index = Isolation(df, 'tractid', 'pop10') + >>> isolation_index.statistic + 0.11321482777341298 + + The interpretation of this number is that if you randomly pick a X member of a specific area, there is 11.32% of probability that this member shares a unit with another X member. + + Notes + ----- + The group of interest is labelled as group X. + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _isolation(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _isolation
+ + + +def _exposure(data, group_pop_var, total_pop_var): + """ + Calculation of Exposure index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Exposure Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + The group of interest is labelled as group X, whilst Y is the complementary group. Groups X and Y are mutually excludent. + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + yi = t - x + + X = x.sum() + xPy = np.nansum((x / X) * (yi / t)) + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return xPy, core_data + + +
[docs]class Exposure: + """ + Classic Exposure Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Exposure Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Exposure Index (xPy) for the Riverside County using the census tract data of 2010. + The group of interest (X) is non-hispanic black people which is the variable nhblk10 in the dataset and the Y group is the other part of the population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import Exposure + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> exposure_index = Exposure(df, 'tractid', 'pop10') + >>> exposure_index.statistic + 0.886785172226587 + + The interpretation of this number is that if you randomly pick a X member of a specific area, there is 88.68% of probability that this member shares a unit with a Y member. + + Notes + ----- + The group of interest is labelled as group X, whilst Y is the complementary group. Groups X and Y are mutually excludent. + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _exposure(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _exposure
+ + + + +def _atkinson(data, group_pop_var, total_pop_var, b = 0.5): + """ + Calculation of Atkinson index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + b : float + The shape parameter, between 0 and 1, that determines how to weight the increments to segregation contributed by different portions of the Lorenz curve. + + Returns + ---------- + + statistic : float + Atkinson Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if (not isinstance(b, float)): + raise ValueError('The parameter b must be a float.') + + if ((b < 0) or (b > 1)): + raise ValueError('The parameter b must be between 0 and 1.') + + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + T = t.sum() + P = x.sum() / T + + # If a unit has zero population, the group of interest frequency is zero + pi = np.where(t == 0, 0, x / t) + + A = 1 - (P / (1-P)) * abs((((1 - pi) ** (1-b) * pi ** b * t) / (P * T)).sum()) ** (1 / (1 - b)) + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return A, core_data + + +
[docs]class Atkinson: + """ + Classic Atkinson Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + b : float + The shape parameter, between 0 and 1, that determines how to weight the increments to segregation contributed by different portions of the Lorenz curve. + + Attributes + ---------- + + statistic : float + Atkison Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Atkinson Index (A) with the shape parameter (b) equals to 0.5 for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import Atkinson + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> atkinson_index = Atkinson(df, 'tractid', 'pop10', b = 0.5) + >>> atkinson_index.statistic + 0.16722406110274002 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, b = 0.5): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _atkinson(data, group_pop_var, total_pop_var, b) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _atkinson
+ + + +def _correlationr(data, group_pop_var, total_pop_var): + """ + Calculation of Correlation Ratio index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Correlation Ratio Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + X = x.sum() + T = t.sum() + P = X / T + + xPx = np.nansum((x / X) * (x / t)) + + V = (xPx - P) / (1 - P) + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return V, core_data + + +
[docs]class CorrelationR: + """ + Classic Correlation Ratio Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest (X) + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Correlation Ratio Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Correlation Ratio Index (V) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import CorrelationR + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> correlationr_index = CorrelationR(df, 'tractid', 'pop10') + >>> correlationr_index.statistic + 0.048716810856363923 + + Notes + ----- + + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _correlationr(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _correlationr
+ + +def _conprof(data, group_pop_var, total_pop_var, m = 1000): + """ + Calculation of Concentration Profile + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + m : int + a numeric value indicating the number of thresholds to be used. Default value is 1000. + A large value of m creates a smoother-looking graph and a more precise concentration profile value but slows down the calculation speed. + + Returns + ---------- + + statistic : float + Concentration Profile Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Hong, Seong-Yun, and Yukio Sadahiro. "Measuring geographic segregation: a graph-based approach." Journal of Geographical Systems 16.2 (2014): 211-231. + + Reference: :cite:`hong2014measuring`. + + """ + if(type(m) is not int): + raise TypeError('m must be a string.') + + if(m < 2): + raise ValueError('m must be greater than 1.') + + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + def calculate_vt(th): + g_t_i = np.where(x / t >= th, 1, 0) + v_t = (g_t_i * x).sum() / x.sum() + return v_t + + grid = np.linspace(0, 1, m) + curve = np.array(list(map(calculate_vt, grid))) + + threshold = x.sum() / t.sum() + R = ((threshold - ((curve[grid < threshold]).sum() / m - (curve[grid >= threshold]).sum()/ m)) / (1 - threshold)) + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return R, grid, curve, core_data + + +
[docs]class ConProf: + """ + Concentration Profile Index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + m : int + a numeric value indicating the number of thresholds to be used. + A large value of m creates a smoother-looking graph and a more precise concentration profile value but slows down the calculation speed. + + Attributes + ---------- + + statistic : float + Concentration Profile Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the concentration profile (R) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import ConProf + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> conprof_index = ConProf(df, 'tractid', 'pop10') + >>> conprof_index.statistic + 0.06393365660089256 + + You can plot the profile curve with the plot method. + + >>> conprof_index.plot() + + Notes + ----- + Based on Hong, Seong-Yun, and Yukio Sadahiro. "Measuring geographic segregation: a graph-based approach." Journal of Geographical Systems 16.2 (2014): 211-231. + + Reference: :cite:`hong2014measuring`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, m = 1000): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _conprof(data, group_pop_var, total_pop_var, m) + + self.statistic = aux[0] + self.grid = aux[1] + self.curve = aux[2] + self.core_data = aux[3] + self._function = _conprof
+ + def plot(self): + """ + Plot the Concentration Profile + """ + try: + import matplotlib.pyplot as plt + except ImportError: + warnings.warn('This method relies on importing `matplotlib`') + graph = plt.scatter(self.grid, self.curve, s = 0.1) + return graph
+ + + + +def _modified_dissim(data, group_pop_var, total_pop_var, iterations = 500): + """ + Calculation of Modified Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + iterations : int + The number of iterations the evaluate average classic dissimilarity under eveness. Default value is 500. + + Returns + ---------- + + statistic : float + Modified Dissimilarity Index (Dissimilarity from Carrington and Troske (1997)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Carrington, William J., and Kenneth R. Troske. "On measuring segregation in samples with small units." Journal of Business & Economic Statistics 15.4 (1997): 402-409. + + Reference: :cite:`carrington1997measuring`. + + """ + if(type(iterations) is not int): + raise TypeError('iterations must be an integer') + + if(iterations < 2): + raise TypeError('iterations must be greater than 1.') + + D = _dissim(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + # core_data has to be in the beggining of the call because assign methods will be used later + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + p_null = x.sum() / t.sum() + + Ds = np.empty(iterations) + + for i in np.array(range(iterations)): + + freq_sim = np.random.binomial(n = np.array([t.tolist()]), + p = np.array([[p_null] * data.shape[0]]), + size = (1, data.shape[0])).tolist()[0] + data = data.assign(group_pop_var = freq_sim) + aux = _dissim(data, 'group_pop_var', 'total_pop_var')[0] + Ds[i] = aux + + D_star = Ds.mean() + + if (D >= D_star): + Dct = (D - D_star)/(1 - D_star) + else: + Dct = (D - D_star)/D_star + + return Dct, core_data + + +
[docs]class ModifiedDissim: + """ + Calculation of Modified Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + iterations : int + The number of iterations the evaluate average classic dissimilarity under eveness. Default value is 500. + + Attributes + ---------- + + statistic : float + Modified Dissimilarity Index (Dissimilarity from Carrington and Troske (1997)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Modified Dissimilarity Index (Dct) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import ModifiedDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> np.random.seed(1234) + >>> modified_dissim_index = ModifiedDissim(df, 'tractid', 'pop10') + >>> modified_dissim_index.statistic + 0.30009504639081996 + + Notes + ----- + Based on Carrington, William J., and Kenneth R. Troske. "On measuring segregation in samples with small units." Journal of Business & Economic Statistics 15.4 (1997): 402-409. + + Reference: :cite:`carrington1997measuring`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, iterations = 500): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _modified_dissim(data, group_pop_var, total_pop_var, iterations) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _modified_dissim
+ + +def _modified_gini_seg(data, group_pop_var, total_pop_var, iterations = 500): + """ + Calculation of Modified Gini Segregation index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + iterations : int + The number of iterations the evaluate average classic gini segregation under eveness. Default value is 500. + + Returns + ---------- + + statistic : float + Modified Gini Segregation Index (Gini from Carrington and Troske (1997)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Carrington, William J., and Kenneth R. Troske. "On measuring segregation in samples with small units." Journal of Business & Economic Statistics 15.4 (1997): 402-409. + + Reference: :cite:`carrington1997measuring`. + + """ + if(type(iterations) is not int): + raise TypeError('iterations must be an integer') + + if(iterations < 2): + raise TypeError('iterations must be greater than 1.') + + G = _gini_seg(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + # core_data has to be in the beggining of the call because assign methods will be used later + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + p_null = x.sum() / t.sum() + + Gs = np.empty(iterations) + + for i in np.array(range(iterations)): + + freq_sim = np.random.binomial(n = np.array([t.tolist()]), + p = np.array([[p_null] * data.shape[0]]), + size = (1, data.shape[0])).tolist()[0] + data = data.assign(group_pop_var = freq_sim) + aux = _gini_seg(data, 'group_pop_var', 'total_pop_var')[0] + Gs[i] = aux + + G_star = Gs.mean() + + if (G >= G_star): + Gct = (G - G_star)/(1 - G_star) + else: + Gct = (G - G_star)/G_star + + return Gct, core_data + + +
[docs]class ModifiedGiniSeg: + """ + Calculation of Modified Gini Segregation index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + iterations : int + The number of iterations the evaluate average classic gini segregation under eveness. Default value is 500. + + Attributes + ---------- + + statistic : float + Modified Gini Segregation Index (Gini from Carrington and Troske (1997)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Modified Gini Segregation Index (Gct) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import ModifiedGiniSeg + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> np.random.seed(1234) + >>> modified_gini_seg_index = ModifiedGiniSeg(df, 'tractid', 'pop10') + >>> modified_gini_seg_index.statistic + 0.4280279611418648 + + Notes + ----- + Based on Carrington, William J., and Kenneth R. Troske. "On measuring segregation in samples with small units." Journal of Business & Economic Statistics 15.4 (1997): 402-409. + + Reference: :cite:`carrington1997measuring`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, iterations = 500): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _modified_gini_seg(data, group_pop_var, total_pop_var, iterations) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _modified_gini_seg
+ + + + +def _bias_corrected_dissim(data, group_pop_var, total_pop_var, B = 500): + """ + Calculation of Bias Corrected Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + B : int + The number of iterations to calculate Dissimilarity simulating randomness with multinomial distributions. Default value is 500. + + Returns + ---------- + + statistic : float + Dissimilarity with Bias-Correction (bias correction from Allen, Rebecca et al. (2015)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Allen, Rebecca, et al. "More reliable inference for the dissimilarity index of segregation." The econometrics journal 18.1 (2015): 40-66. + + Reference: :cite:`allen2015more`. + + """ + if(type(B) is not int): + raise TypeError('B must be an integer') + + if(B < 2): + raise TypeError('B must be greater than 1.') + + D = _dissim(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + other_group_pop = t - x + + # Group 0: minority group + p0_i = x / x.sum() + n0 = x.sum() + sim0 = np.random.multinomial(n0, p0_i, size = B) + + # Group 1: complement group + p1_i = other_group_pop / other_group_pop.sum() + n1 = other_group_pop.sum() + sim1 = np.random.multinomial(n1, p1_i, size = B) + + + Dbcs = np.empty(B) + for i in np.array(range(B)): + data_aux = {'simul_group': sim0[i].tolist(), 'simul_tot': (sim0[i] + sim1[i]).tolist()} + df_aux = pd.DataFrame.from_dict(data_aux) + Dbcs[i] = _dissim(df_aux, 'simul_group', 'simul_tot')[0] + + Db = Dbcs.mean() + + Dbc = 2 * D - Db + Dbc # It expected to be lower than D, because D is upwarded biased + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return Dbc, core_data + + +
[docs]class BiasCorrectedDissim: + """ + Calculation of Bias Corrected Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + B : int + The number of iterations to calculate Dissimilarity simulating randomness with multinomial distributions. Default value is 500. + + Attributes + ---------- + + statistic : float + Dissimilarity with Bias-Correction (bias correction from Allen, Rebecca et al. (2015)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Dissimilarity with Bias Correction (Dbc) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import BiasCorrectedDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> np.random.seed(1234) + >>> bias_corrected_dissim_index = BiasCorrectedDissim(df, 'tractid', 'pop10') + >>> bias_corrected_dissim_index.statistic + 0.31484636081876954 + + Notes + ----- + Based on Allen, Rebecca, et al. "More reliable inference for the dissimilarity index of segregation." The econometrics journal 18.1 (2015): 40-66. + + Reference: :cite:`allen2015more`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, B = 500): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _bias_corrected_dissim(data, group_pop_var, total_pop_var, B) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _bias_corrected_dissim
+ + +def _density_corrected_dissim(data, group_pop_var, total_pop_var, xtol = 1e-5): + """ + Calculation of Density Corrected Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + xtol : float + The degree of tolerance in the optimization process of returning optimal theta_j + + Returns + ---------- + + statistic : float + Dissimilarity with Density-Correction (density correction from Allen, Rebecca et al. (2015)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Allen, Rebecca, et al. "More reliable inference for the dissimilarity index of segregation." The econometrics journal 18.1 (2015): 40-66. + + Reference: :cite:`allen2015more`. + + """ + if((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) or (total_pop_var not in data.columns)): + raise ValueError('group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + g = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < g): + raise ValueError('Group of interest population must equal or lower than the total population of the units.') + + other_group_pop = t - g + + # Group 0: minority group + p0_i = g / g.sum() + n0 = g.sum() + + # Group 1: complement group + p1_i = other_group_pop / other_group_pop.sum() + n1 = other_group_pop.sum() + + sigma_hat_j = np.sqrt(((p1_i * (1 - p1_i)) / n1) + ((p0_i * (1 - p0_i)) / n0)) + theta_hat_j = abs(p1_i - p0_i) / sigma_hat_j + + # Constructing function that returns $n(\hat{\theta}_j)$ + def return_optimal_theta(theta_j): + + def fold_norm(x): + y = (-1) * (norm.pdf(x - theta_j) + norm.pdf(x + theta_j)) + return y + + initial_guesses = np.array(0) + res = minimize(fold_norm, + initial_guesses, + method='nelder-mead', + options = {'xtol': xtol}) + return res.final_simplex[0][1][0] + + optimal_thetas = pd.Series(data = theta_hat_j).apply(return_optimal_theta) + + Ddc = np.multiply(sigma_hat_j, optimal_thetas).sum() / 2 + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + core_data = data[['group_pop_var', 'total_pop_var']] + + else: + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return Ddc, core_data + + +
[docs]class DensityCorrectedDissim: + """ + Calculation of Density Corrected Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + xtol : float + The degree of tolerance in the optimization process of returning optimal theta_j + + Attributes + ---------- + + statistic : float + Dissimilarity with Density-Correction (density correction from Allen, Rebecca et al. (2015)) + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the Dissimilarity with Density Correction (Ddc) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.aspatial import DensityCorrectedDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['pop10','tractid']] + + The value is estimated below. + + >>> density_corrected_dissim_index = DensityCorrectedDissim(df, 'tractid', 'pop10') + >>> density_corrected_dissim_index.statistic + 0.29350643204887517 + + Notes + ----- + Based on Allen, Rebecca, et al. "More reliable inference for the dissimilarity index of segregation." The econometrics journal 18.1 (2015): 40-66. + + Reference: :cite:`allen2015more`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, xtol = 1e-5): + + if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + else: + data = _nan_handle(data[[group_pop_var, total_pop_var]]) + + aux = _density_corrected_dissim(data, group_pop_var, total_pop_var, xtol) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _density_corrected_dissim
+ + + + + + + + + + + + + +# Deprecation Calls + +msg = _dep_message("Gini_Seg", "GiniSeg") +Gini_Seg = DeprecationHelper(GiniSeg, message=msg) + +msg = _dep_message("Correlation_R", "CorrelationR") +Correlation_R = DeprecationHelper(CorrelationR, message=msg) + +msg = _dep_message("Con_Prof", "ConProf") +Con_Prof = DeprecationHelper(ConProf, message=msg) + +msg = _dep_message("Modified_Dissim", "ModifiedDissim") +Modified_Dissim = DeprecationHelper(ModifiedDissim, message=msg) + +msg = _dep_message("Modified_Gini_Seg", "ModifiedGiniSeg") +Modified_Gini_Seg = DeprecationHelper(ModifiedGiniSeg, message=msg) + +msg = _dep_message("Bias_Corrected_Dissim", "BiasCorrectedDissim") +Bias_Corrected_Dissim = DeprecationHelper(BiasCorrectedDissim, message=msg) + +msg = _dep_message("Density_Corrected_Dissim", "DensityCorrectedDissim") +Density_Corrected_Dissim = DeprecationHelper(DensityCorrectedDissim, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/aspatial/multigroup_aspatial_indexes.html b/docs/_modules/segregation/aspatial/multigroup_aspatial_indexes.html new file mode 100644 index 00000000..728e3544 --- /dev/null +++ b/docs/_modules/segregation/aspatial/multigroup_aspatial_indexes.html @@ -0,0 +1,1335 @@ + + + + + + + segregation.aspatial.multigroup_aspatial_indexes — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.aspatial.multigroup_aspatial_indexes

+"""
+Multigroup Aspatial based Segregation Metrics
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu>, Sergio J. Rey <sergio.rey@ucr.edu> and Elijah Knaap <elijah.knaap@ucr.edu>"
+
+import numpy as np
+from sklearn.metrics.pairwise import manhattan_distances
+
+from segregation.util.util import _dep_message, DeprecationHelper, _nan_handle
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = [
+    'Multi_Dissim', 
+    'MultiDissim',
+    
+    'Multi_Gini_Seg', 
+    'MultiGiniSeg', 
+    
+    'Multi_Normalized_Exposure',
+    'MultiNormalizedExposure',
+    
+    'Multi_Information_Theory', 
+    'MultiInformationTheory', 
+    
+    'Multi_Relative_Diversity',
+    'MultiRelativeDiversity',
+    
+    'Multi_Squared_Coefficient_of_Variation', 
+    'MultiSquaredCoefficientVariation',
+    
+    'Multi_Diversity',
+    'MultiDiversity',
+    
+    'Simpsons_Concentration', 
+    'SimpsonsConcentration', 
+    
+    'Simpsons_Interaction', 
+    'SimpsonsInteraction', 
+    
+    'Multi_Divergence',
+    'MultiDivergence'
+]
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+# suppress numpy divide by zero warnings because it occurs a lot during the
+# calculation of many indices
+np.seterr(divide='ignore', invalid='ignore')
+
+
+def _multi_dissim(data, groups):
+    """
+    Calculation of Multigroup Dissimilarity index
+
+    Parameters
+    ----------
+
+    data   : a pandas DataFrame
+    
+    groups : list of strings.
+             The variables names in data of the groups of interest of the analysis.
+
+    Returns
+    -------
+
+    statistic : float
+                Multigroup Dissimilarity Index
+                
+    core_data : a pandas DataFrame
+                A pandas DataFrame that contains the columns used to perform the estimate.
+
+    Notes
+    -----
+    Based on Sakoda, James M. "A generalized index of dissimilarity." Demography 18.2 (1981): 245-250.
+    
+    Reference: :cite:`sakoda1981generalized`.
+
+    """
+
+    core_data = data[groups]
+    data = _nan_handle(core_data)
+
+    df = np.array(core_data)
+
+    n = df.shape[0]
+    K = df.shape[1]
+
+    T = df.sum()
+
+    ti = df.sum(axis=1)
+    pik = df / ti[:, None]
+    Pk = df.sum(axis=0) / df.sum()
+
+    Is = (Pk * (1 - Pk)).sum()
+
+    multi_D = 1 / (2 * T * Is) * np.multiply(
+        abs(pik - Pk),
+        np.repeat(ti, K, axis=0).reshape(n, K)).sum()
+
+    return multi_D, core_data, groups
+
+
+
[docs]class MultiDissim: + """ + Calculation of Multigroup Dissimilarity index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Dissimilarity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiDissim + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiDissim(input_df, groups_list) + >>> index.statistic + 0.41340872573177806 + + Notes + ----- + Based on Sakoda, James M. "A generalized index of dissimilarity." Demography 18.2 (1981): 245-250. + + Reference: :cite:`sakoda1981generalized`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_dissim(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_dissim
+ + +def _multi_gini_seg(data, groups): + """ + Calculation of Multigroup Gini Segregation index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Gini Segregation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + K = df.shape[1] + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + Is = (Pk * (1 - Pk)).sum() + + elements_sum = np.empty(K) + for k in range(K): + aux = np.multiply(np.outer(ti, ti), + manhattan_distances(pik[:, k].reshape(-1, 1))).sum() + elements_sum[k] = aux + + multi_Gini_Seg = elements_sum.sum() / (2 * (T**2) * Is) + + return multi_Gini_Seg, core_data, groups + + +
[docs]class MultiGiniSeg: + """ + Calculation of Multigroup Gini Segregation index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Gini Segregation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiGiniSeg + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiGiniSeg(input_df, groups_list) + >>> index.statistic + 0.5456349992598081 + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_gini_seg(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_gini_seg
+ + +def _multi_normalized_exposure(data, groups): + """ + Calculation of Multigroup Normalized Exposure index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Normalized Exposure Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + + MNE = ((ti[:, None] * (pik - Pk)**2) / (1 - Pk)).sum() / T + + return MNE, core_data, groups + + +
[docs]class MultiNormalizedExposure: + """ + Calculation of Multigroup Normalized Exposure index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Normalized Exposure Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiNormalizedExposure + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiNormalizedExposure(input_df, groups_list) + >>> index.statistic + 0.18821879029994157 + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_normalized_exposure(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_normalized_exposure
+ + +def _multi_information_theory(data, groups): + """ + Calculation of Multigroup Information Theory index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Information Theory Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + + # The natural logarithm is used, but this could be used with any base following Footnote 3 of pg. 37 + # of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + E = (Pk * np.log(1 / Pk)).sum() + + MIT = np.nansum(ti[:, None] * pik * np.log(pik / Pk)) / (T * E) + + return MIT, core_data, groups + + +
[docs]class MultiInformationTheory: + """ + Calculation of Multigroup Information Theory index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Information Theory Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiInformationTheory + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiInformationTheory(input_df, groups_list) + >>> index.statistic + 0.1710160297858887 + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_information_theory(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_information_theory
+ + +def _multi_relative_diversity(data, groups): + """ + Calculation of Multigroup Relative Diversity index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Relative Diversity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Reardon, Sean F. "Measures of racial diversity and segregation in multigroup and hierarchically structured populations." annual meeting of the Eastern Sociological Society, Philadelphia, PA. 1998. + + High diversity means less segregation. + + Reference: :cite:`reardon1998measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + Is = (Pk * (1 - Pk)).sum() + + MRD = (ti[:, None] * (pik - Pk)**2).sum() / (T * Is) + + return MRD, core_data, groups + + +
[docs]class MultiRelativeDiversity: + """ + Calculation of Multigroup Relative Diversity index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Relative Diversity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiRelativeDiversity + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiRelativeDiversity(input_df, groups_list) + >>> index.statistic + 0.15820019878220337 + + Notes + ----- + Based on Reardon, Sean F. "Measures of racial diversity and segregation in multigroup and hierarchically structured populations." annual meeting of the Eastern Sociological Society, Philadelphia, PA. 1998. + + High diversity means less segregation. + + Reference: :cite:`reardon1998measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_relative_diversity(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_relative_diversity
+ + +def _multi_squared_coefficient_of_variation(data, groups): + """ + Calculation of Multigroup Squared Coefficient of Variation index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Squared Coefficient of Variation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + K = df.shape[1] + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + + C = ((ti[:, None] * (pik - Pk)**2) / (T * (K - 1) * Pk)).sum() + + return C, core_data, groups + + +
[docs]class MultiSquaredCoefficientVariation: + """ + Calculation of Multigroup Squared Coefficient of Variation index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Squared Coefficient of Variation Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiSquaredCoefficientVariation + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiSquaredCoefficientVariation(input_df, groups_list) + >>> index.statistic + 0.11875484641127525 + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_squared_coefficient_of_variation(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_squared_coefficient_of_variation
+ + +def _multi_diversity(data, groups, normalized=False): + """ + Calculation of Multigroup Diversity index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Diversity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + normalized : bool. Default is False. + Wheter the resulting index will be divided by its maximum (natural log of the number of groups) + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67 and Theil, Henry. "Statistical decomposition analysis; with applications in the social and administrative sciences". No. 04; HA33, T4.. 1972. + + This is also know as Theil's Entropy Index (Equation 2 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67) + + High diversity means less segregation. + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + Pk = df.sum(axis=0) / df.sum() + + E = -(Pk * np.log(Pk)).sum() + + if normalized: + K = df.shape[1] + E = E / np.log(K) + + return E, core_data, groups + + +
[docs]class MultiDiversity: + """ + Calculation of Multigroup Diversity index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Diversity Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiDiversity + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiDiversity(input_df, groups_list) + >>> index.statistic + 0.9733112243997906 + + You can also fit the normalized version of the multigroup diversity index. + + >>> normalized_index = Multi_Diversity(input_df, groups_list, normalized = True) + >>> normalized_index.statistic + 0.7020956383415715 + + Notes + ----- + Based on Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67 and Theil, Henry. "Statistical decomposition analysis; with applications in the social and administrative sciences". No. 04; HA33, T4.. 1972. + + This is also know as Theil's Entropy Index (Equation 2 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67) + + High diversity means less segregation. + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups, normalized=False): + + aux = _multi_diversity(data, groups, normalized) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_diversity
+ + +def _simpsons_concentration(data, groups): + """ + Calculation of Simpson's Concentration index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Simpson's Concentration Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Simpson, Edward H. "Measurement of diversity." nature 163.4148 (1949): 688. + + Simpson's concentration index (Lambda) can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to belong to the same group. + + Higher values means higher segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`simpson1949measurement`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + Pk = df.sum(axis=0) / df.sum() + + Lambda = (Pk * Pk).sum() + + return Lambda, core_data, groups + + +
[docs]class SimpsonsConcentration: + """ + Calculation of Simpson's Concentration index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Simpson's Concentration Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import SimpsonsConcentration + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = SimpsonsConcentration(input_df, groups_list) + >>> index.statistic + 0.49182413151957904 + + Notes + ----- + Based on Simpson, Edward H. "Measurement of diversity." nature 163.4148 (1949): 688. + + Simpson's concentration index (Lambda) can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to belong to the same group. + + Higher values means higher segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`simpson1949measurement`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _simpsons_concentration(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _simpsons_concentration
+ + +def _simpsons_interaction(data, groups): + """ + Calculation of Simpson's Interaction index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Simpson's Interaction Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's interaction index (I) can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to not belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + Pk = df.sum(axis=0) / df.sum() + + I = (Pk * (1 - Pk)).sum() + + return I, core_data, groups + + +
[docs]class SimpsonsInteraction: + """ + Calculation of Simpson's Interaction index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Simpson's Interaction Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import SimpsonsInteraction + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = SimpsonsInteraction(input_df, groups_list) + >>> index.statistic + 0.508175868480421 + + Notes + ----- + Based on Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's interaction index (I) can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to not belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _simpsons_interaction(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _simpsons_interaction
+ + +def _multi_divergence(data, groups): + """ + Calculation of Multigroup Divergence index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistic : float + Multigroup Divergence Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Roberto, Elizabeth. "The Divergence Index: A Decomposable Measure of Segregation and Inequality." arXiv preprint arXiv:1508.01167 (2015). + + Reference: :cite:`roberto2015divergence`. + + """ + + core_data = data[groups] + data = _nan_handle(core_data) + + df = np.array(core_data) + + T = df.sum() + + ti = df.sum(axis=1) + pik = df / ti[:, None] + Pk = df.sum(axis=0) / df.sum() + + Di = np.nansum(pik * np.log(pik / Pk), axis=1) + + Divergence_Index = ((ti / T) * Di).sum() + + return Divergence_Index, core_data, groups + + +
[docs]class MultiDivergence: + """ + Calculation of Multigroup Divergence index + + Parameters + ---------- + + data : a pandas DataFrame + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistic : float + Multigroup Divergence Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.multigroup_aspatial import MultiDivergence + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiDivergence(input_df, groups_list) + >>> index.statistic + 0.16645182134289443 + + Notes + ----- + Based on Roberto, Elizabeth. "The Divergence Index: A Decomposable Measure of Segregation and Inequality." arXiv preprint arXiv:1508.01167 (2015). + + Reference: :cite:`roberto2015divergence`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_divergence(data, groups) + + self.statistic = aux[0] + self.core_data = aux[1] + self._groups = aux[2] + self._function = _multi_divergence
+ + + + +# Deprecation Calls + +msg = _dep_message("Multi_Dissim", "MultiDissim") +Multi_Dissim = DeprecationHelper(MultiDissim, message=msg) + +msg = _dep_message("Multi_Gini_Seg", "MultiGiniSeg") +Multi_Gini_Seg = DeprecationHelper(MultiGiniSeg, message=msg) + +msg = _dep_message("Multi_Normalized_Exposure", "MultiNormalizedExposure") +Multi_Normalized_Exposure = DeprecationHelper(MultiNormalizedExposure, message=msg) + +msg = _dep_message("Multi_Information_Theory", "MultiInformationTheory") +Multi_Information_Theory = DeprecationHelper(MultiInformationTheory, message=msg) + +msg = _dep_message("Multi_Relative_Diversity", "MultiRelativeDiversity") +Multi_Relative_Diversity = DeprecationHelper(MultiRelativeDiversity, message=msg) + +msg = _dep_message("Multi_Squared_Coefficient_of_Variation", "MultiSquaredCoefficientVariation") +Multi_Squared_Coefficient_of_Variation = DeprecationHelper(MultiSquaredCoefficientVariation, message=msg) + +msg = _dep_message("Multi_Diversity", "MultiDiversity") +Multi_Diversity = DeprecationHelper(MultiDiversity, message=msg) + +msg = _dep_message("Simpsons_Concentration", "SimpsonsConcentration") +Simpsons_Concentration = DeprecationHelper(SimpsonsConcentration, message=msg) + +msg = _dep_message("Simpsons_Interaction", "SimpsonsInteraction") +Simpsons_Interaction = DeprecationHelper(SimpsonsInteraction, message=msg) + +msg = _dep_message("Multi_Divergence", "MultiDivergence") +Multi_Divergence = DeprecationHelper(MultiDivergence, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/compute_all/compute_all.html b/docs/_modules/segregation/compute_all/compute_all.html new file mode 100644 index 00000000..3ddc4908 --- /dev/null +++ b/docs/_modules/segregation/compute_all/compute_all.html @@ -0,0 +1,483 @@ + + + + + + + segregation.compute_all.compute_all — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.compute_all.compute_all

+"""
+Compute Several Segregation measures at once
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu> and Sergio J. Rey <sergio.rey@ucr.edu>"
+
+import pandas as pd
+from segregation.aspatial import *
+from segregation.spatial import *
+
+__all__ = [
+    'ComputeAllAspatialSegregation', 
+    'ComputeAllSpatialSegregation',
+    'ComputeAllSegregation'
+]
+
+
+def _compute_all_aspatial_segregation(data, group_pop_var, total_pop_var):
+    '''
+    Perform point estimation of selected aspatial segregation measures at once
+
+    Parameters
+    ----------
+
+    data          : a pandas DataFrame
+    
+    group_pop_var : string
+                    The name of variable in data that contains the population size of the group of interest
+                    
+    total_pop_var : string
+                    The name of variable in data that contains the total population of the unit
+    
+    Returns
+    -------
+
+    computed      : a pandas DataFrame containing the name of the measure and the point estimation.
+    
+    Notes
+    -----
+    Currently, works with the default input parameters of the functions.
+    
+    '''
+
+    D = Dissim(data, group_pop_var, total_pop_var)
+    G = GiniSeg(data, group_pop_var, total_pop_var)
+    H = Entropy(data, group_pop_var, total_pop_var)
+    A = Atkinson(data, group_pop_var, total_pop_var)
+    xPy = Exposure(data, group_pop_var, total_pop_var)
+    xPx = Isolation(data, group_pop_var, total_pop_var)
+    R = ConProf(data, group_pop_var, total_pop_var)
+    Dbc = BiasCorrectedDissim(data, group_pop_var, total_pop_var)
+    Ddc = DensityCorrectedDissim(data, group_pop_var, total_pop_var)
+    V = CorrelationR(data, group_pop_var, total_pop_var)
+    Dct = ModifiedDissim(data, group_pop_var, total_pop_var)
+    Gct = ModifiedGiniSeg(data, group_pop_var, total_pop_var)
+    MM = MinMax(data, group_pop_var, total_pop_var)
+
+    dictionary = {
+        'Dissimilarity': D.statistic,
+        'Gini': G.statistic,
+        'Entropy': H.statistic,
+        'Atkinson': A.statistic,
+        'Exposure': xPy.statistic,
+        'Isolation': xPx.statistic,
+        'Concentration Profile': R.statistic,
+        'Bias Corrected Dissimilarity': Dbc.statistic,
+        'Density Corrected Dissimilarity': Ddc.statistic,
+        'Correlation Ratio': V.statistic,
+        'Modified Dissimilarity': Dct.statistic,
+        'Modified Gini': Gct.statistic,
+        'Minimun-Maximum': MM.statistic
+    }
+    
+    d = {'Measure': list(dictionary.keys()), 'Value': list(dictionary.values())}
+
+    computed = pd.DataFrame(data = d)
+
+    return computed
+
+
+
[docs]class ComputeAllAspatialSegregation: + ''' + Perform point estimation of selected Aspatial segregation measures at once + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + computed : a pandas DataFrame containing the name of the measure and the point estimation. + + Examples + -------- + The Compute_All comprises simple and quick functions to assess multiple segregation measures at once in a dataset. It uses all the default parameters and returns an object that has an attribute (.computed) of a dictionary with summary of all values fitted. + + Firstly, we need to import the libraries and functions to be used. + + >>> import geopandas as gpd + >>> import segregation + >>> import libpysal + >>> from segregation.util import ComputeAllAspatialSegregation + + Then it's time to load some data to estimate segregation. We use the data of 2000 Census Tract Data for the metropolitan area of Sacramento, CA, USA. + + We use a geopandas dataframe available in PySAL examples repository. + + For more information about the data: https://github.com/pysal/libpysal/tree/master/libpysal/examples/sacramento2 + + >>> s_map = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + + The data have several demographic variables. We are going to assess the segregation of the Hispanic Population (variable 'HISP_'). For this, we only extract some columns of the geopandas dataframe. + + >>> gdf = s_map[['geometry', 'HISP_', 'TOT_POP']] + + Now the measures are fitted. + + >>> aspatial_fit = ComputeAllAspatialSegregation(gdf, 'HISP_', 'TOT_POP') + >>> aspatial_fit.computed + + ''' + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + aux = _compute_all_aspatial_segregation(data, group_pop_var, + total_pop_var) + + self.computed = aux
+ + +def _compute_all_spatial_segregation(data, group_pop_var, total_pop_var): + ''' + Perform point estimation of selected spatial segregation measures at once + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + computed : a pandas DataFrame containing the name of the measure and the point estimation. + + ''' + + SD = SpatialDissim(data, group_pop_var, total_pop_var) + PARD = PerimeterAreaRatioSpatialDissim(data, group_pop_var, + total_pop_var) + BSD = BoundarySpatialDissim(data, group_pop_var, total_pop_var) + ACE = AbsoluteCentralization(data, group_pop_var, total_pop_var) + ACO = AbsoluteConcentration(data, group_pop_var, total_pop_var) + DEL = Delta(data, group_pop_var, total_pop_var) + RCE = RelativeCentralization(data, group_pop_var, total_pop_var) + ACL = AbsoluteClustering(data, group_pop_var, total_pop_var) + RCL = RelativeClustering(data, group_pop_var, total_pop_var) + RCO = RelativeConcentration(data, group_pop_var, total_pop_var) + DDxPy = DistanceDecayExposure(data, group_pop_var, total_pop_var) + DDxPx = DistanceDecayIsolation(data, group_pop_var, total_pop_var) + SPP = SpatialProxProf(data, group_pop_var, total_pop_var) + SP = SpatialProximity(data, group_pop_var, total_pop_var) + SMM = SpatialMinMax(data, group_pop_var, total_pop_var) + + dictionary = { + 'Spatial Dissimilarity': SD.statistic, + 'Absolute Centralization': ACE.statistic, + 'Absolute Clustering': ACL.statistic, + 'Absolute Concentration': ACO.statistic, + 'Delta': DEL.statistic, + 'Relative Centralization': RCE.statistic, + 'Relative Clustering': RCL.statistic, + 'Relative Concentration': RCO.statistic, + 'Distance Decay Exposure': DDxPy.statistic, + 'Distance Decay Isolation': DDxPx.statistic, + 'Spatial Proximity Profile': SPP.statistic, + 'Spatial Proximity': SP.statistic, + 'Boundary Spatial Dissimilarity': BSD.statistic, + 'Perimeter Area Ratio Spatial Dissimilarity': PARD.statistic, + 'Spatial Minimun-Maximum': SMM.statistic + } + + d = {'Measure': list(dictionary.keys()), 'Value': list(dictionary.values())} + + computed = pd.DataFrame(data = d) + + return computed + + +
[docs]class ComputeAllSpatialSegregation: + ''' + Perform point estimation of selected spatial segregation measures at once + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + computed : a pandas DataFrame containing the name of the measure and the point estimation. + + Examples + -------- + The Compute_All comprises simple and quick functions to assess multiple segregation measures at once in a dataset. It uses all the default parameters and returns an object that has an attribute (.computed) of a dictionary with summary of all values fitted. + + Firstly, we need to import the libraries and functions to be used. + + >>> import geopandas as gpd + >>> import segregation + >>> import libpysal + >>> from segregation.util import ComputeAllSpatialSegregation + + Then it's time to load some data to estimate segregation. We use the data of 2000 Census Tract Data for the metropolitan area of Sacramento, CA, USA. + + We use a geopandas dataframe available in PySAL examples repository. + + For more information about the data: https://github.com/pysal/libpysal/tree/master/libpysal/examples/sacramento2 + + >>> s_map = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + + The data have several demographic variables. We are going to assess the segregation of the Hispanic Population (variable 'HISP_'). For this, we only extract some columns of the geopandas dataframe. + + >>> gdf = s_map[['geometry', 'HISP_', 'TOT_POP']] + + Now the measures are fitted. + + >>> spatial_fit = ComputeAllSpatialSegregation(gdf, 'HISP_', 'TOT_POP') + >>> spatial_fit.computed + + ''' + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + aux = _compute_all_spatial_segregation(data, group_pop_var, total_pop_var) + + self.computed = aux
+ + +def _compute_all_segregation(data, group_pop_var, total_pop_var): + ''' + Perform point estimation of selected segregation measures at once + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + computed : a pandas DataFrame containing the name of the measure and the point estimation. + + ''' + + x = ComputeAllAspatialSegregation(data, group_pop_var, + total_pop_var).computed + y = ComputeAllSpatialSegregation(data, group_pop_var, total_pop_var).computed + + z = pd.concat([x, y], ignore_index = True) + + return z + + +
[docs]class ComputeAllSegregation: + ''' + Perform point estimation of selected segregation measures at once + + Parameters + ---------- + + data : a pandas DataFrame + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + computed : a pandas DataFrame containing the name of the measure and the point estimation. + + Examples + -------- + The Compute_All comprises simple and quick functions to assess multiple segregation measures at once in a dataset. It uses all the default parameters and returns an object that has an attribute (.computed) of a dictionary with summary of all values fitted. + + Firstly, we need to import the libraries and functions to be used. + + >>> import geopandas as gpd + >>> import segregation + >>> import libpysal + >>> from segregation.util import ComputeAllSegregation + + Then it's time to load some data to estimate segregation. We use the data of 2000 Census Tract Data for the metropolitan area of Sacramento, CA, USA. + + We use a geopandas dataframe available in PySAL examples repository. + + For more information about the data: https://github.com/pysal/libpysal/tree/master/libpysal/examples/sacramento2 + + >>> s_map = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + + The data have several demographic variables. We are going to assess the segregation of the Hispanic Population (variable 'HISP_'). For this, we only extract some columns of the geopandas dataframe. + + >>> gdf = s_map[['geometry', 'HISP_', 'TOT_POP']] + + Now the measures are fitted. + + >>> segregation_fit = ComputeAllSegregation(gdf, 'HISP_', 'TOT_POP') + >>> segregation_fit.computed + + ''' + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + aux = _compute_all_segregation(data, group_pop_var, total_pop_var) + + self.computed = aux
+
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/decomposition/decompose_segregation.html b/docs/_modules/segregation/decomposition/decompose_segregation.html new file mode 100644 index 00000000..288319b2 --- /dev/null +++ b/docs/_modules/segregation/decomposition/decompose_segregation.html @@ -0,0 +1,449 @@ + + + + + + + segregation.decomposition.decompose_segregation — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.decomposition.decompose_segregation

+"""
+Decomposition Segregation based Metrics
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu>, Elijah Knaap <elijah.knaap@ucr.edu>, and Sergio J. Rey <sergio.rey@ucr.edu>"
+
+
+import warnings
+from segregation.util.util import _generate_counterfactual, _dep_message, DeprecationHelper
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = ['Decompose_Segregation',
+           'DecomposeSegregation']
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+def _decompose_segregation(index1,
+                           index2,
+                           counterfactual_approach='composition'):
+    """Decompose segregation differences into spatial and attribute components.
+
+    Given two segregation indices of the same type, use Shapley decomposition
+    to measure whether the differences between index measures arise from
+    differences in spatial structure or population structure
+
+    Parameters
+    ----------
+    index1 : segregation.SegIndex class
+        First SegIndex class to compare.
+    index2 : segregation.SegIndex class
+        Second SegIndex class to compare.
+    counterfactual_approach : str, one of
+                              ["composition", "share", "dual_composition"]
+        The technique used to generate the counterfactual population
+        distributions.
+
+    Returns
+    -------
+    tuple
+        (shapley spatial component,
+         shapley attribute component,
+         core data of index1,
+         core data of index2,
+         data with counterfactual variables for index1,
+         data with counterfactual variables for index2)
+
+    """
+    df1 = index1.core_data.copy()
+    df2 = index2.core_data.copy()
+
+    assert index1._function == index2._function, "Segregation indices must be of the same type"
+
+    counterfac_df1, counterfac_df2 = _generate_counterfactual(
+        df1,
+        df2,
+        'group_pop_var',
+        'total_pop_var',
+        counterfactual_approach=counterfactual_approach)
+
+    seg_func = index1._function
+
+    # index for spatial 1, attribute 1
+    G_S1_A1 = index1.statistic
+
+    # index for spatial 2, attribute 2
+    G_S2_A2 = index2.statistic
+
+    # index for spatial 1 attribute 2 (counterfactual population for structure 1)
+    G_S1_A2 = seg_func(counterfac_df1, 'counterfactual_group_pop',
+                       'counterfactual_total_pop')[0]
+
+    # index for spatial 2 attribute 1 (counterfactual population for structure 2)
+    G_S2_A1 = seg_func(counterfac_df2, 'counterfactual_group_pop',
+                       'counterfactual_total_pop')[0]
+
+    # take the average difference in spatial structure, holding attributes constant
+    C_S = 1 / 2 * (G_S1_A1 - G_S2_A1 + G_S1_A2 - G_S2_A2)
+
+    # take the average difference in attributes, holding spatial structure constant
+    C_A = 1 / 2 * (G_S1_A1 - G_S1_A2 + G_S2_A1 - G_S2_A2)
+
+    results = {'s1_a1': G_S1_A1,
+            's1_a2': G_S1_A2,
+            's2_a1': G_S2_A1,
+            's2_a2': G_S2_A2 }
+
+    return C_S, C_A, df1, df2, counterfac_df1, counterfac_df2, counterfactual_approach, results
+
+
+
[docs]class DecomposeSegregation: + """Decompose segregation differences into spatial and attribute components. + + Given two segregation indices of the same type, use Shapley decomposition + to measure whether the differences between index measures arise from + differences in spatial structure or population structure + + Parameters + ---------- + index1 : segregation.SegIndex class + First SegIndex class to compare. + index2 : segregation.SegIndex class + Second SegIndex class to compare. + counterfactual_approach : str, one of + ["composition", "share", "dual_composition"] + The technique used to generate the counterfactual population + distributions. + + Attributes + ---------- + + c_s : float + Shapley's Spatial Component of the decomposition + + c_a : float + Shapley's Attribute Component of the decomposition + + Methods + ---------- + + plot : Visualize features of the Decomposition performed + plot_type : str, one of ['cdfs', 'maps'] + + 'cdfs' : visualize the cumulative distribution functions of the compositions/shares + 'maps' : visualize the spatial distributions for original data and counterfactuals generated and Shapley's components (only available for GeoDataFrames) + + Examples + -------- + Several examples can be found at https://github.com/pysal/segregation/blob/master/notebooks/decomposition_wrapper_example.ipynb. + + """ + +
[docs] def __init__(self, index1, index2, counterfactual_approach='composition'): + + aux = _decompose_segregation(index1, index2, counterfactual_approach) + + self.c_s = aux[0] + self.c_a = aux[1] + self._df1 = aux[2] + self._df2 = aux[3] + self._counterfac_df1 = aux[4] + self._counterfac_df2 = aux[5] + self._counterfactual_approach = aux[6] + self.indices = aux[7]
+ + def plot(self, plot_type='cdfs'): + """ + Plot the Segregation Decomposition Profile + """ + try: + import matplotlib.pyplot as plt + except ImportError: + warnings.warn('This method relies on importing `matplotlib`') + + if (plot_type == 'cdfs'): + if (self._counterfactual_approach == 'composition'): + plt.suptitle( + 'Spatial Component = {}, Attribute Component: {}'.format( + round(self.c_s, 3), round(self.c_a, 3)), + size=20) + plt.step( + self._counterfac_df1['group_composition'].sort_values(), + self._counterfac_df1['group_composition'].rank( + pct=True).sort_values(), + label='First Context Group Composition') + + plt.step( + self._counterfac_df2['group_composition'].sort_values(), + self._counterfac_df2['group_composition'].rank( + pct=True).sort_values(), + label='Second Context Group Composition') + plt.legend() + + if (self._counterfactual_approach == 'share'): + plt.suptitle( + 'Spatial Component = {}, Attribute Component: {}'.format( + round(self.c_s, 3), round(self.c_a, 3)), + size=20) + plt.step((self._df1['group_pop_var'] / + self._df1['group_pop_var'].sum()).sort_values(), + (self._df1['group_pop_var'] / + self._df1['group_pop_var'].sum()).rank( + pct=True).sort_values(), + label='First Context Group Share') + + plt.step((self._df2['group_pop_var'] / + self._df2['group_pop_var'].sum()).sort_values(), + (self._df2['group_pop_var'] / + self._df2['group_pop_var'].sum()).rank( + pct=True).sort_values(), + label='Second Context Group Share') + + plt.step( + ((self._df1['total_pop_var'] - self._df1['group_pop_var']) + / (self._df1['total_pop_var'] - + self._df1['group_pop_var']).sum()).sort_values(), + ((self._df1['total_pop_var'] - self._df1['group_pop_var']) + / (self._df1['total_pop_var'] - + self._df1['group_pop_var']).sum()).rank( + pct=True).sort_values(), + label='First Context Complementary Group Share') + + plt.step( + ((self._df2['total_pop_var'] - self._df2['group_pop_var']) + / (self._df2['total_pop_var'] - + self._df2['group_pop_var']).sum()).sort_values(), + ((self._df2['total_pop_var'] - self._df2['group_pop_var']) + / (self._df2['total_pop_var'] - + self._df2['group_pop_var']).sum()).rank( + pct=True).sort_values(), + label='Second Context Complementary Group Share') + plt.legend() + + if (self._counterfactual_approach == 'dual_composition'): + plt.suptitle( + 'Spatial Component = {}, Attribute Component: {}'.format( + round(self.c_s, 3), round(self.c_a, 3)), + size=20) + plt.step( + self._counterfac_df1['group_composition'].sort_values(), + self._counterfac_df1['group_composition'].rank( + pct=True).sort_values(), + label='First Context Group Composition') + + plt.step( + self._counterfac_df2['group_composition'].sort_values(), + self._counterfac_df2['group_composition'].rank( + pct=True).sort_values(), + label='Second Context Group Composition') + + plt.step( + (1 - + self._counterfac_df1['group_composition']).sort_values(), + (1 - self._counterfac_df1['group_composition']).rank( + pct=True).sort_values(), + label='First Context Complementary Group Composition') + + plt.step( + (1 - + self._counterfac_df2['group_composition']).sort_values(), + (1 - self._counterfac_df2['group_composition']).rank( + pct=True).sort_values(), + label='Second Context Complementary Group Composition') + + plt.legend() + + if (plot_type == 'maps'): + if (str(type(self._df1)) != + '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, maps cannot be draw.' + ) + + # Subplots + fig, axs = plt.subplots(2, 2, figsize=(10, 10)) + + fig.suptitle( + 'Spatial Component = {}, Attribute Component: {}'.format( + round(self.c_s, 3), round(self.c_a, 3)), + size=20) + fig.subplots_adjust(hspace=1.25, wspace=0.2, + top=0.95) # hspace space between lines + fig.tight_layout(rect=[ + 0, 0, 1, 0.925 + ]) # rect is to position the suptitle above the subplots + + # Original First Context (Upper Left) + self._counterfac_df1.plot(column='group_composition', + cmap='OrRd', + legend=True, + ax=axs[0, 0]) + axs[0, 0].title.set_text('Original First Context Composition') + axs[0, 0].axis('off') + + # Counterfactual First Context (Bottom Left) + self._counterfac_df1.plot(column='counterfactual_composition', + cmap='OrRd', + legend=True, + ax=axs[1, 0]) + axs[1, 0].title.set_text( + 'Counterfactual First Context Composition') + axs[1, 0].axis('off') + + # Counterfactual Second Context (Upper Right) + self._counterfac_df2.plot(column='counterfactual_composition', + cmap='OrRd', + legend=True, + ax=axs[0, 1]) + axs[0, 1].title.set_text( + 'Counterfactual Second Context Composition') + axs[0, 1].axis('off') + + # Original Second Context (Bottom Right) + self._counterfac_df2.plot(column='group_composition', + cmap='OrRd', + legend=True, + ax=axs[1, 1]) + axs[1, 1].title.set_text('Original Second Context Composition') + axs[1, 1].axis('off')
+ + + + + + + + +# Deprecation Calls + +msg = _dep_message("Decompose_Segregation", "DecomposeSegregation") +Decompose_Segregation = DeprecationHelper(DecomposeSegregation, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/inference/inference_wrappers.html b/docs/_modules/segregation/inference/inference_wrappers.html new file mode 100644 index 00000000..f414702d --- /dev/null +++ b/docs/_modules/segregation/inference/inference_wrappers.html @@ -0,0 +1,880 @@ + + + + + + + segregation.inference.inference_wrappers — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.inference.inference_wrappers

+"""
+Inference Wrappers for Segregation measures
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu> Sergio J. Rey <sergio.rey@ucr.edu> and Elijah Knaap <elijah.knaap@ucr.edu>"
+
+import numpy as np
+import pandas as pd
+import geopandas as gpd
+import warnings
+from tqdm.auto import tqdm
+from segregation.util.util import _generate_counterfactual, _dep_message, DeprecationHelper
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = [
+    'Infer_Segregation', 'SingleValueTest', 'Compare_Segregation',
+    'TwoValueTest'
+]
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+
+def _infer_segregation(seg_class,
+                       iterations_under_null=500,
+                       null_approach="systematic",
+                       two_tailed=True,
+                       **kwargs):
+    '''
+    Perform inference for a single segregation measure
+
+    Parameters
+    ----------
+
+    seg_class                    : a PySAL segregation object
+    
+    iterations_under_null        : number of iterations under null hyphothesis
+    
+    null_approach : argument that specifies which type of null hypothesis the inference will iterate. Please take a look at Notes (1).
+    
+        "systematic"             : assumes that every group has the same probability with restricted conditional probabilities p_0_j = p_1_j = p_j = n_j/n (multinomial distribution).
+        "bootstrap"              : generates bootstrap replications of the units with replacement of the same size of the original data.
+        "evenness"               : assumes that each spatial unit has the same global probability of drawing elements from the minority group of the fixed total unit population (binomial distribution).
+        
+        "permutation"            : randomly allocates the units over space keeping the original values.
+        
+        "systematic_permutation" : assumes absence of systematic segregation and randomly allocates the units over space.
+        "even_permutation"       : assumes the same global probability of drawning elements from the minority group in each spatial unit and randomly allocates the units over space.
+    
+    two_tailed    : boolean. Please take a look at Notes (2).
+                    If True, p_value is two-tailed. Otherwise, it is right one-tailed.
+    
+    **kwargs      : customizable parameters to pass to the segregation measures. Usually they need to be the same input that the seg_class was built.
+    
+    Attributes
+    ----------
+
+    p_value     : float
+                  Pseudo One or Two-Tailed p-value estimated from the simulations
+    
+    est_sim     : numpy array
+                  Estimates of the segregation measure under the null hypothesis
+                  
+    statistic   : float
+                  The point estimation of the segregation measure that is under test
+                
+    Notes
+    -----
+    
+    1) The different approaches for the null hypothesis affect directly the results of the inference depending on the combination of the index type of seg_class and the null_approach chosen.
+    Therefore, the user needs to be aware of how these approaches are affecting the data generation process of the simulations in order to draw meaningful conclusions. 
+    For example, the Modified Dissimilarity (ModifiedDissim) and  Modified Gini (ModifiedGiniSeg) indexes, rely exactly on the distance between evenness through sampling which, therefore, the "evenness" value for null approach would not be the most appropriate for these indexes.
+    
+    2) The one-tailed p_value attribute might not be appropriate for some measures, as the two-tailed. Therefore, it is better to rely on the est_sim attribute.
+    
+    '''
+    if not null_approach in [
+            'systematic', 'bootstrap', 'evenness', 'permutation',
+            'systematic_permutation', 'even_permutation'
+    ]:
+        raise ValueError(
+            'null_approach must one of \'systematic\', \'bootstrap\', \'evenness\', \'permutation\', \'systematic_permutation\', \'even_permutation\''
+        )
+
+    if (type(two_tailed) is not bool):
+        raise TypeError('two_tailed is not a boolean object')
+
+    point_estimation = seg_class.statistic
+    data = seg_class.core_data.copy()
+
+    aux = str(type(seg_class))
+    _class_name = aux[1 + aux.rfind(
+        '.'):-2]  # 'rfind' finds the last occurence of a pattern in a string
+
+    Estimates_Stars = np.empty(iterations_under_null)
+
+    ##############
+    # SYSTEMATIC #
+    ##############
+    if (null_approach == "systematic"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+
+            data['other_group_pop'] = data['total_pop_var'] - data['group_pop_var']
+            p_j = data['total_pop_var'] / data['total_pop_var'].sum()
+    
+            # Group 0: minority group
+            p0_i = p_j
+            n0 = data['group_pop_var'].sum()
+            sim0 = np.random.multinomial(n0, p0_i, size=iterations_under_null)
+    
+            # Group 1: complement group
+            p1_i = p_j
+            n1 = data['other_group_pop'].sum()
+            sim1 = np.random.multinomial(n1, p1_i, size=iterations_under_null)
+    
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+                    data_aux = {
+                        'simul_group': sim0[i].tolist(),
+                        'simul_tot': (sim0[i] + sim1[i]).tolist()
+                    }
+                    df_aux = pd.DataFrame.from_dict(data_aux)
+    
+                    if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+                        df_aux = gpd.GeoDataFrame(df_aux)
+                        df_aux['geometry'] = data['geometry']
+    
+                    Estimates_Stars[i] = seg_class._function(df_aux, 'simul_group', 'simul_tot', **kwargs)[0]
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+                    
+        if ('multigroup' in str(type(seg_class))):
+            raise ValueError('Not implemented for MultiGroup indexes.')
+
+    #############
+    # BOOTSTRAP #
+    #############
+    if (null_approach == "bootstrap"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+    
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+    
+                    sample_index = np.random.choice(data.index, size=len(data), replace=True)
+                    df_aux = data.iloc[sample_index]
+                    Estimates_Stars[i] = seg_class._function(df_aux, 'group_pop_var', 'total_pop_var', **kwargs)[0]
+    
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+
+        if ('multigroup' in str(type(seg_class))):
+            
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+    
+                    sample_index = np.random.choice(data.index, size=len(data), replace=True)
+                    df_aux = data.iloc[sample_index]
+                    Estimates_Stars[i] = seg_class._function(df_aux, seg_class._groups, **kwargs)[0]
+    
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+
+    ############
+    # EVENNESS #
+    ############
+    if (null_approach == "evenness"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+
+            p_null = data['group_pop_var'].sum() / data['total_pop_var'].sum()
+    
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+                    sim = np.random.binomial(n=np.array([data['total_pop_var'].tolist()]),p=p_null)
+                    data_aux = {
+                        'simul_group': sim[0],
+                        'simul_tot': data['total_pop_var'].tolist()
+                    }
+                    df_aux = pd.DataFrame.from_dict(data_aux)
+    
+                    if (str(type(data)) == '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+                        df_aux = gpd.GeoDataFrame(df_aux)
+                        df_aux['geometry'] = data['geometry']
+    
+                    Estimates_Stars[i] = seg_class._function(df_aux, 'simul_group', 'simul_tot', **kwargs)[0]
+    
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+                    
+        if ('multigroup' in str(type(seg_class))):
+            
+            df = np.array(seg_class.core_data)
+            global_prob_vector = df.sum(axis = 0) / df.sum()
+            t = df.sum(axis = 1)
+            
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+            
+                    simul = map(lambda i: list(np.random.multinomial(i, global_prob_vector)), t)
+                    df_simul = pd.DataFrame(list(simul), columns = seg_class._groups)
+                    
+                    Estimates_Stars[i] = seg_class._function(df_simul, seg_class._groups, **kwargs)[0]
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+
+    ###############
+    # PERMUTATION #
+    ###############
+    if (null_approach == "permutation"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+
+            if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+                raise TypeError('data is not a GeoDataFrame, therefore, this null approach does not apply.')
+    
+            with tqdm(total=iterations_under_null) as pbar:
+    
+                for i in np.array(range(iterations_under_null)):
+                    data = data.assign(geometry=data['geometry'][list(np.random.choice(data.shape[0], data.shape[0],replace=False))].reset_index()['geometry'])
+                    df_aux = data
+                    Estimates_Stars[i] = seg_class._function(df_aux, 'group_pop_var', 'total_pop_var', **kwargs)[0]
+                    pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null))
+                    pbar.update(1)
+                    
+        if ('multigroup' in str(type(seg_class))):
+            raise ValueError('Not implemented for MultiGroup indexes.')
+            
+    ##########################
+    # SYSTEMATIC PERMUTATION #
+    ##########################
+    if (null_approach == "systematic_permutation"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+
+            if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+                raise TypeError('data is not a GeoDataFrame, therefore, this null approach does not apply.')
+    
+            data['other_group_pop'] = data['total_pop_var'] - data['group_pop_var']
+            p_j = data['total_pop_var'] / data['total_pop_var'].sum()
+    
+            # Group 0: minority group
+            p0_i = p_j
+            n0 = data['group_pop_var'].sum()
+            sim0 = np.random.multinomial(n0, p0_i, size=iterations_under_null)
+    
+            # Group 1: complement group
+            p1_i = p_j
+            n1 = data['other_group_pop'].sum()
+            sim1 = np.random.multinomial(n1, p1_i, size=iterations_under_null)
+    
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+                    data_aux = {
+                        'simul_group': sim0[i].tolist(),
+                        'simul_tot': (sim0[i] + sim1[i]).tolist()
+                    }
+                    df_aux = pd.DataFrame.from_dict(data_aux)
+                    df_aux = gpd.GeoDataFrame(df_aux)
+                    df_aux['geometry'] = data['geometry']
+                    df_aux = df_aux.assign(geometry=df_aux['geometry'][list(
+                        np.random.choice(
+                            df_aux.shape[0], df_aux.shape[0],
+                            replace=False))].reset_index()['geometry'])
+                    Estimates_Stars[i] = seg_class._function(
+                        df_aux, 'simul_group', 'simul_tot', **kwargs)[0]
+    
+                    pbar.set_description(
+                        'Processed {} iterations out of {}'.format(
+                            i + 1, iterations_under_null))
+                    pbar.update(1)
+                    
+        if ('multigroup' in str(type(seg_class))):
+            raise ValueError('Not implemented for MultiGroup indexes.')
+            
+    ########################
+    # EVENNESS PERMUTATION #
+    ########################
+    if (null_approach == "even_permutation"):
+        
+        if ('multigroup' not in str(type(seg_class))):
+
+            if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+                raise TypeError('data is not a GeoDataFrame, therefore, this null approach does not apply.')
+    
+            p_null = data['group_pop_var'].sum() / data['total_pop_var'].sum()
+    
+            with tqdm(total=iterations_under_null) as pbar:
+                for i in np.array(range(iterations_under_null)):
+                    sim = np.random.binomial(n=np.array(
+                        [data['total_pop_var'].tolist()]),
+                                             p=p_null)
+                    data_aux = {
+                        'simul_group': sim[0],
+                        'simul_tot': data['total_pop_var'].tolist()
+                    }
+                    df_aux = pd.DataFrame.from_dict(data_aux)
+                    df_aux = gpd.GeoDataFrame(df_aux)
+                    df_aux['geometry'] = data['geometry']
+                    df_aux = df_aux.assign(geometry=df_aux['geometry'][list(
+                        np.random.choice(
+                            df_aux.shape[0], df_aux.shape[0],
+                            replace=False))].reset_index()['geometry'])
+                    Estimates_Stars[i] = seg_class._function(
+                        df_aux, 'simul_group', 'simul_tot', **kwargs)[0]
+                    pbar.set_description(
+                        'Processed {} iterations out of {}'.format(
+                            i + 1, iterations_under_null))
+                    pbar.update(1)
+                    
+        if ('multigroup' in str(type(seg_class))):
+            raise ValueError('Not implemented for MultiGroup indexes.')
+            
+    # Check and, if the case, remove iterations_under_null that resulted in nan or infinite values
+    if any((np.isinf(Estimates_Stars) | np.isnan(Estimates_Stars))):
+        warnings.warn(
+            'Some estimates resulted in NaN or infinite values for estimations under null hypothesis. These values will be removed for the final results.'
+        )
+        Estimates_Stars = Estimates_Stars[~(np.isinf(Estimates_Stars)
+                                            | np.isnan(Estimates_Stars))]
+
+    if not two_tailed:
+        p_value = sum(
+            Estimates_Stars > point_estimation) / iterations_under_null
+    else:
+        aux1 = (point_estimation < Estimates_Stars).sum()
+        aux2 = (point_estimation > Estimates_Stars).sum()
+        p_value = 2 * np.array([aux1, aux2]).min() / len(Estimates_Stars)
+
+    return p_value, Estimates_Stars, point_estimation, _class_name
+
+
+
[docs]class SingleValueTest: + ''' + Perform inference for a single segregation measure + + Parameters + ---------- + + seg_class : a PySAL segregation object + + iterations_under_null : number of iterations under null hyphothesis + + null_approach : argument that specifies which type of null hypothesis the inference will iterate. Please take a look at Notes (1). + + "systematic" : assumes that every group has the same probability with restricted conditional probabilities p_0_j = p_1_j = p_j = n_j/n (multinomial distribution). + "bootstrap" : generates bootstrap replications of the units with replacement of the same size of the original data. + "evenness" : assumes that each spatial unit has the same global probability of drawing elements from the minority group of the fixed total unit population (binomial distribution). + + "permutation" : randomly allocates the units over space keeping the original values. + + "systematic_permutation" : assumes absence of systematic segregation and randomly allocates the units over space. + "even_permutation" : assumes the same global probability of drawning elements from the minority group in each spatial unit and randomly allocates the units over space. + + two_tailed : boolean. Please take a look at Notes (2). + If True, p_value is two-tailed. Otherwise, it is right one-tailed. + + **kwargs : customizable parameters to pass to the segregation measures. Usually they need to be the same input that the seg_class was built. + + Attributes + ---------- + + p_value : float + Pseudo One or Two-Tailed p-value estimated from the simulations + + est_sim : numpy array + Estimates of the segregation measure under the null hypothesis + + statistic : float + The point estimation of the segregation measure that is under test + + Notes + ----- + + 1) The different approaches for the null hypothesis affect directly the results of the inference depending on the combination of the index type of seg_class and the null_approach chosen. + Therefore, the user needs to be aware of how these approaches are affecting the data generation process of the simulations in order to draw meaningful conclusions. + For example, the Modified Dissimilarity (ModifiedDissim) and Modified Gini (ModifiedGiniSeg) indexes, rely exactly on the distance between evenness through sampling which, therefore, the "evenness" value for null approach would not be the most appropriate for these indexes. + + 2) The one-tailed p_value attribute might not be appropriate for some measures, as the two-tailed. Therefore, it is better to rely on the est_sim attribute. + + Examples + -------- + Several examples can be found here https://github.com/pysal/segregation/blob/master/notebooks/inference_wrappers_example.ipynb. + + ''' + +
[docs] def __init__(self, + seg_class, + iterations_under_null=500, + null_approach="systematic", + two_tailed=True, + **kwargs): + + aux = _infer_segregation(seg_class, iterations_under_null, + null_approach, two_tailed, **kwargs) + + self.p_value = aux[0] + self.est_sim = aux[1] + self.statistic = aux[2] + self._class_name = aux[3]
+ + def plot(self, ax=None): + """ + Plot the Infer_Segregation class + """ + try: + import matplotlib.pyplot as plt + import seaborn as sns + except ImportError: + warnings.warn( + 'This method relies on importing `matplotlib` and `seaborn`') + + f = sns.distplot(self.est_sim, + hist=True, + color='darkblue', + hist_kws={'edgecolor': 'black'}, + kde_kws={'linewidth': 2}, + ax=ax) + plt.axvline(self.statistic, color='red') + plt.title('{} (Value = {})'.format(self._class_name, + round(self.statistic, 3))) + return f
+ + +def _compare_segregation(seg_class_1, + seg_class_2, + iterations_under_null=500, + null_approach="random_label", + **kwargs): + ''' + Perform inference comparison for a two segregation measures + + Parameters + ---------- + + seg_class_1 : a PySAL segregation object to be compared to seg_class_2 + + seg_class_2 : a PySAL segregation object to be compared to seg_class_1 + + iterations_under_null : number of iterations under null hyphothesis + + null_approach: argument that specifies which type of null hypothesis the inference will iterate. + + "random_label" : random label the data in each iteration + + "counterfactual_composition" : randomizes the number of minority population according to both cumulative distribution function of a variable that represents the composition of the minority group. The composition is the division of the minority population of unit i divided by total population of tract i. + + "counterfactual_share" : randomizes the number of minority population and total population according to both cumulative distribution function of a variable that represents the share of the minority group. The share is the division of the minority population of unit i divided by total population of minority population. + + "counterfactual_dual_composition" : applies the "counterfactual_composition" for both minority and complementary groups. + + **kwargs : customizable parameters to pass to the segregation measures. Usually they need to be the same as both seg_class_1 and seg_class_2 was built. + + Attributes + ---------- + + p_value : float + Two-Tailed p-value + + est_sim : numpy array + Estimates of the segregation measure differences under the null hypothesis + + est_point_diff : float + Point estimation of the difference between the segregation measures + + Notes + ----- + This function performs inference to compare two segregation measures. This can be either two measures of the same locations in two different points in time or it can be two different locations at the same point in time. + + The null hypothesis is H0: Segregation_1 is not different than Segregation_2. + + Based on Rey, Sergio J., and Myrna L. Sastré-Gutiérrez. "Interregional inequality dynamics in Mexico." Spatial Economic Analysis 5.3 (2010): 277-298. + + ''' + + if not null_approach in [ + 'random_label', 'counterfactual_composition', + 'counterfactual_share', 'counterfactual_dual_composition' + ]: + raise ValueError( + 'null_approach must one of \'random_label\', \'counterfactual_composition\', \'counterfactual_share\', \'counterfactual_dual_composition\'' + ) + + if (type(seg_class_1) != type(seg_class_2)): + raise TypeError('seg_class_1 and seg_class_2 must be the same type/class.') + + point_estimation = seg_class_1.statistic - seg_class_2.statistic + + aux = str(type(seg_class_1)) + _class_name = aux[1 + aux.rfind('.'):-2] # 'rfind' finds the last occurence of a pattern in a string + + data_1 = seg_class_1.core_data.copy() + data_2 = seg_class_2.core_data.copy() + + est_sim = np.empty(iterations_under_null) + + ################ + # RANDOM LABEL # + ################ + if (null_approach == "random_label"): + + data_1['grouping_variable'] = 'Group_1' + data_2['grouping_variable'] = 'Group_2' + + if ('multigroup' not in str(type(seg_class_1))): + + # This step is just to make sure the each frequecy column is integer for the approaches and from the same type in order to be able to stack them + data_1['group_pop_var'] = round(data_1['group_pop_var']).astype(int) + data_1['total_pop_var'] = round(data_1['total_pop_var']).astype(int) + + data_2['group_pop_var'] = round(data_2['group_pop_var']).astype(int) + data_2['total_pop_var'] = round(data_2['total_pop_var']).astype(int) + + stacked_data = pd.concat([data_1, data_2], ignore_index=True) + + with tqdm(total=iterations_under_null) as pbar: + for i in np.array(range(iterations_under_null)): + + stacked_data['grouping_variable'] = np.random.permutation(stacked_data['grouping_variable']) + + stacked_data_1 = stacked_data.loc[stacked_data['grouping_variable'] == 'Group_1'] + stacked_data_2 = stacked_data.loc[stacked_data['grouping_variable'] == 'Group_2'] + + simulations_1 = seg_class_1._function(stacked_data_1,'group_pop_var','total_pop_var',**kwargs)[0] + simulations_2 = seg_class_2._function(stacked_data_2,'group_pop_var','total_pop_var',**kwargs)[0] + + est_sim[i] = simulations_1 - simulations_2 + pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null)) + pbar.update(1) + + if ('multigroup' in str(type(seg_class_1))): + + groups_list = seg_class_1._groups + + for i in range(len(groups_list)): + data_1[groups_list[i]] = round(data_1[groups_list[i]]).astype(int) + data_2[groups_list[i]] = round(data_2[groups_list[i]]).astype(int) + + if (seg_class_1._groups != seg_class_2._groups): + raise ValueError('MultiGroup groups should be the same') + + stacked_data = pd.concat([data_1, data_2], ignore_index=True) + + with tqdm(total=iterations_under_null) as pbar: + for i in np.array(range(iterations_under_null)): + + stacked_data['grouping_variable'] = np.random.permutation(stacked_data['grouping_variable']) + + stacked_data_1 = stacked_data.loc[stacked_data['grouping_variable'] == 'Group_1'] + stacked_data_2 = stacked_data.loc[stacked_data['grouping_variable'] == 'Group_2'] + + simulations_1 = seg_class_1._function(stacked_data_1, groups_list, **kwargs)[0] + simulations_2 = seg_class_2._function(stacked_data_2, groups_list, **kwargs)[0] + + est_sim[i] = simulations_1 - simulations_2 + pbar.set_description('Processed {} iterations out of {}'.format(i + 1, iterations_under_null)) + pbar.update(1) + + + ############################## + # COUNTERFACTUAL COMPOSITION # + ############################## + if (null_approach in ['counterfactual_composition', 'counterfactual_share','counterfactual_dual_composition']): + + if ('multigroup' in str(type(seg_class_1))): + raise ValueError('Not implemented for MultiGroup indexes.') + + internal_arg = null_approach[15:] # Remove 'counterfactual_' from the beginning of the string + + counterfac_df1, counterfac_df2 = _generate_counterfactual( + data_1, + data_2, + 'group_pop_var', + 'total_pop_var', + counterfactual_approach=internal_arg) + + if (null_approach in [ + 'counterfactual_share', 'counterfactual_dual_composition' + ]): + data_1['total_pop_var'] = counterfac_df1[ + 'counterfactual_total_pop'] + data_2['total_pop_var'] = counterfac_df2[ + 'counterfactual_total_pop'] + with tqdm(total=iterations_under_null) as pbar: + for i in np.array(range(iterations_under_null)): + + data_1['fair_coin'] = np.random.uniform(size=len(data_1)) + data_1['test_group_pop_var'] = np.where( + data_1['fair_coin'] > 0.5, data_1['group_pop_var'], + counterfac_df1['counterfactual_group_pop']) + + # Dropping to avoid confusion in the internal function + data_1_test = data_1.drop(['group_pop_var'], axis=1) + + simulations_1 = seg_class_1._function(data_1_test, + 'test_group_pop_var', + 'total_pop_var', + **kwargs)[0] + + # Dropping to avoid confusion in the next iteration + data_1 = data_1.drop(['fair_coin', 'test_group_pop_var'], + axis=1) + + data_2['fair_coin'] = np.random.uniform(size=len(data_2)) + data_2['test_group_pop_var'] = np.where( + data_2['fair_coin'] > 0.5, data_2['group_pop_var'], + counterfac_df2['counterfactual_group_pop']) + + # Dropping to avoid confusion in the internal function + data_2_test = data_2.drop(['group_pop_var'], axis=1) + + simulations_2 = seg_class_2._function(data_2_test, + 'test_group_pop_var', + 'total_pop_var', + **kwargs)[0] + + # Dropping to avoid confusion in the next iteration + data_2 = data_2.drop(['fair_coin', 'test_group_pop_var'], + axis=1) + + est_sim[i] = simulations_1 - simulations_2 + + pbar.set_description( + 'Processed {} iterations out of {}'.format( + i + 1, iterations_under_null)) + pbar.update(1) + + # Check and, if the case, remove iterations_under_null that resulted in nan or infinite values + if any((np.isinf(est_sim) | np.isnan(est_sim))): + warnings.warn( + 'Some estimates resulted in NaN or infinite values for estimations under null hypothesis. These values will be removed for the final results.' + ) + est_sim = est_sim[~(np.isinf(est_sim) | np.isnan(est_sim))] + + # Two-Tailed p-value + # Obs.: the null distribution can be located far from zero. Therefore, this is the the appropriate way to calculate the two tailed p-value. + aux1 = (point_estimation < est_sim).sum() + aux2 = (point_estimation > est_sim).sum() + p_value = 2 * np.array([aux1, aux2]).min() / len(est_sim) + + return p_value, est_sim, point_estimation, _class_name + + +
[docs]class TwoValueTest: + ''' + Perform inference comparison for a two segregation measures + + Parameters + ---------- + + seg_class_1 : a PySAL segregation object to be compared to seg_class_2 + + seg_class_2 : a PySAL segregation object to be compared to seg_class_1 + + iterations_under_null : number of iterations under null hyphothesis + + null_approach : argument that specifies which type of null hypothesis the inference will iterate. + + "random_label" : random label the data in each iteration + + "counterfactual_composition" : randomizes the number of minority population according to both cumulative distribution function of a variable that represents the composition of the minority group. The composition is the division of the minority population of unit i divided by total population of tract i. + + "counterfactual_share" : randomizes the number of minority population and total population according to both cumulative distribution function of a variable that represents the share of the minority group. The share is the division of the minority population of unit i divided by total population of minority population. + + "counterfactual_dual_composition" : applies the "counterfactual_composition" for both minority and complementary groups. + + **kwargs : customizable parameters to pass to the segregation measures. Usually they need to be the same as both seg_class_1 and seg_class_2 was built. + + Attributes + ---------- + + p_value : float + Two-Tailed p-value + + est_sim : numpy array + Estimates of the segregation measure differences under the null hypothesis + + est_point_diff : float + Point estimation of the difference between the segregation measures + + Notes + ----- + This function performs inference to compare two segregation measures. This can be either two measures of the same locations in two different points in time or it can be two different locations at the same point in time. + + The null hypothesis is H0: Segregation_1 is not different than Segregation_2. + + Based on Rey, Sergio J., and Myrna L. Sastré-Gutiérrez. "Interregional inequality dynamics in Mexico." Spatial Economic Analysis 5.3 (2010): 277-298. + + Examples + -------- + Several examples can be found here https://github.com/pysal/segregation/blob/master/notebooks/inference_wrappers_example.ipynb. + + ''' + +
[docs] def __init__(self, + seg_class_1, + seg_class_2, + iterations_under_null=500, + null_approach="random_label", + **kwargs): + + aux = _compare_segregation(seg_class_1, seg_class_2, + iterations_under_null, null_approach, + **kwargs) + + self.p_value = aux[0] + self.est_sim = aux[1] + self.est_point_diff = aux[2] + self._class_name = aux[3]
+ + def plot(self, ax=None): + """ + Plot the Compare_Segregation class + """ + try: + import matplotlib.pyplot as plt + import seaborn as sns + except ImportError: + warnings.warn( + 'This method relies on importing `matplotlib` and `seaborn`') + + f = sns.distplot(self.est_sim, + hist=True, + color='darkblue', + hist_kws={'edgecolor': 'black'}, + kde_kws={'linewidth': 2}, + ax=ax) + plt.axvline(self.est_point_diff, color='red') + plt.title('{} (Diff. value = {})'.format(self._class_name, + round(self.est_point_diff, + 3))) + return f
+ + +# Deprecation Calls + +msg = _dep_message("Infer_Segregation", "SingleValueTest") +Infer_Segregation = DeprecationHelper(SingleValueTest, message=msg) + +msg = _dep_message("Compare_Segregation", "TwoValueTest") +Compare_Segregation = DeprecationHelper(TwoValueTest, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/local/local_indexes.html b/docs/_modules/segregation/local/local_indexes.html new file mode 100644 index 00000000..dce60cbb --- /dev/null +++ b/docs/_modules/segregation/local/local_indexes.html @@ -0,0 +1,879 @@ + + + + + + + segregation.local.local_indexes — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.local.local_indexes

+"""
+Local based Segregation Metrics
+
+Important: all classes that start with "Multi_" expects a specific type of input of multigroups since the index will be calculated using many groups.
+On the other hand, other classes expects a single group for calculation of the metrics.
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu>, Elijah Knaap <elijah.knaap@ucr.edu> and Sergio J. Rey <sergio.rey@ucr.edu>"
+
+import numpy as np
+import libpysal as lps
+
+from segregation.spatial import RelativeCentralization
+
+from segregation.util.util import _dep_message, DeprecationHelper
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = [
+    'Multi_Location_Quotient',
+    'MultiLocationQuotient',
+    
+    'Multi_Local_Diversity',
+    'MultiLocalDiversity',
+    
+    'Multi_Local_Entropy',
+    'MultiLocalEntropy',
+    
+    'Multi_Local_Simpson_Interaction',
+    'MultiLocalSimpsonInteraction',
+    
+    'Multi_Local_Simpson_Concentration',
+    'MultiLocalSimpsonConcentration',
+    
+    'Local_Relative_Centralization',
+    'LocalRelativeCentralization'
+]
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+
+
+
+# suppress numpy divide by zero warnings because it occurs a lot during the
+# calculation of many indices
+np.seterr(divide='ignore', invalid='ignore')
+
+def _multi_location_quotient(data, groups):
+    """
+    Calculation of Location Quotient index for each group and unit
+
+    Parameters
+    ----------
+
+    data   : a pandas DataFrame of n rows
+    
+    groups : list of strings of length k.
+             The variables names in data of the groups of interest of the analysis.
+
+    Returns
+    -------
+
+    statistics : np.array(n,k)
+                 Location Quotient values for each group and unit.
+                 Column k has the Location Quotient of position k in groups.
+                
+    core_data  : a pandas DataFrame
+                 A pandas DataFrame that contains the columns used to perform the estimate.
+
+    Notes
+    -----
+    Based on Isard, Walter. Methods of regional analysis. Vol. 4. Рипол КлаÑÑик, 1967.
+    
+    Reference: :cite:`isard1967methods`.
+
+    """
+    
+    core_data = data[groups]
+    
+    df = np.array(core_data)
+    
+    n = df.shape[0]
+    K = df.shape[1]
+    
+    T = df.sum()
+    
+    ti = df.sum(axis = 1)
+    Xk = df.sum(axis = 0)
+    
+    multi_LQ = (df / np.repeat(ti, K, axis = 0).reshape(n,K)) / (Xk / T)
+    
+    return multi_LQ, core_data
+
+
+
[docs]class MultiLocationQuotient: + """ + Calculation of Location Quotient index for each group and unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings of length k. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistics : np.array(n,k) + Location Quotient values for each group and unit. + Column k has the Location Quotient of position k in groups. + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import MultiLocationQuotient + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiLocationQuotient(input_df, groups_list) + >>> index.statistics[0:3,0:3] + array([[1.36543221, 0.07478049, 0.16245651], + [1.18002164, 0. , 0.14836683], + [0.68072696, 0.03534425, 0. ]]) + + Important to note that column k has the Location Quotient (LQ) of position k in groups. Therefore, the LQ of the first unit of 'WHITE_' is 1.36543221. + + Notes + ----- + Based on Isard, Walter. Methods of regional analysis. Vol. 4. Рипол КлаÑÑик, 1967. + + Reference: :cite:`isard1967methods`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_location_quotient(data, groups) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _multi_location_quotient
+ + + + +def _multi_local_diversity(data, groups): + """ + Calculation of Local Diversity index for each group and unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings of length k. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistics : np.array(n,k) + Local Diversity values for each group and unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Theil, Henry. Statistical decomposition analysis; with applications in the social and administrative sciences. No. 04; HA33, T4.. 1972. + + Reference: :cite:`theil1972statistical`. + + """ + + core_data = data[groups] + + df = np.array(core_data) + + ti = df.sum(axis = 1) + pik = df/ti[:,None] + + multi_LD = - np.nansum(pik * np.log(pik), axis = 1) + + return multi_LD, core_data + + +
[docs]class MultiLocalDiversity: + """ + Calculation of Local Diversity index for each group and unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings of length k. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistics : np.array(n,k) + Local Diversity values for each group and unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import MultiLocalDiversity + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiLocalDiversity(input_df, groups_list) + >>> index.statistics[0:10] # Values of first 10 units + array([0.34332326, 0.56109229, 0.70563225, 0.29713472, 0.22386084, + 0.29742517, 0.12322789, 0.11274579, 0.09402405, 0.25129616]) + + Notes + ----- + Based on Theil, Henry. Statistical decomposition analysis; with applications in the social and administrative sciences. No. 04; HA33, T4.. 1972. + + Reference: :cite:`theil1972statistical`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_local_diversity(data, groups) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _multi_local_diversity
+ + +def _multi_local_entropy(data, groups): + """ + Calculation of Local Entropy index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistics : np.array(n) + Local Entropy values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Eq. 6 of pg. 139 (individual unit case) of Reardon, Sean F., and David O’Sullivan. "Measures of spatial segregation." Sociological methodology 34.1 (2004): 121-162. + + Reference: :cite:`reardon2004measures`. + + """ + + core_data = data[groups] + + df = np.array(core_data) + + K = df.shape[1] + + ti = df.sum(axis = 1) + pik = df/ti[:,None] + + multi_LE = - np.nansum((pik * np.log(pik)) / np.log(K), axis = 1) + + return multi_LE, core_data + + +
[docs]class MultiLocalEntropy: + """ + Calculation of Local Entropy index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistics : np.array(n) + Local Entropy values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import MultiLocalEntropy + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiLocalEntropy(input_df, groups_list) + >>> index.statistics[0:10] # Values of first 10 units + array([0.24765538, 0.40474253, 0.50900607, 0.21433739, 0.16148146, + 0.21454691, 0.08889013, 0.08132889, 0.06782401, 0.18127186]) + + Notes + ----- + Based on Eq. 6 of pg. 139 (individual unit case) of Reardon, Sean F., and David O’Sullivan. "Measures of spatial segregation." Sociological methodology 34.1 (2004): 121-162. + + Reference: :cite:`reardon2004measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_local_entropy(data, groups) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _multi_local_entropy
+ + + +def _multi_local_simpson_interaction(data, groups): + """ + Calculation of Local Simpson Interaction index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistics : np.array(n) + Local Simpson Interaction values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on the local version of Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's interaction index can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to not belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + + df = np.array(core_data) + + ti = df.sum(axis = 1) + pik = df/ti[:,None] + + local_SI = np.nansum(pik * (1 - pik), axis = 1) + + return local_SI, core_data + + +
[docs]class MultiLocalSimpsonInteraction: + """ + Calculation of Local Simpson Interaction index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistics : np.array(n) + Local Simpson Interaction values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import MultiLocalSimpsonInteraction + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiLocalSimpsonInteraction(input_df, groups_list) + >>> index.statistics[0:10] # Values of first 10 units + array([0.15435993, 0.33391595, 0.49909747, 0.1299449 , 0.09805056, + 0.13128178, 0.04447356, 0.0398933 , 0.03723054, 0.11758548]) + + Notes + ----- + Based on the local version of Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's interaction index can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to not belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_local_simpson_interaction(data, groups) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _multi_local_simpson_interaction
+ + +def _multi_local_simpson_concentration(data, groups): + """ + Calculation of Local Simpson concentration index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Returns + ------- + + statistics : np.array(n) + Local Simpson concentration values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on the local version of Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's concentration index can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + + core_data = data[groups] + + df = np.array(core_data) + + ti = df.sum(axis = 1) + pik = df/ti[:,None] + + local_SC = np.nansum(pik * pik, axis = 1) + + return local_SC, core_data + + +
[docs]class MultiLocalSimpsonConcentration: + """ + Calculation of Local Simpson concentration index for each unit + + Parameters + ---------- + + data : a pandas DataFrame of n rows + + groups : list of strings. + The variables names in data of the groups of interest of the analysis. + + Attributes + ---------- + + statistics : np.array(n) + Local Simpson concentration values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The groups of interest are White, Black, Asian and Hispanic population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import MultiLocalSimpsonConcentration + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + >>> groups_list = ['WHITE_', 'BLACK_', 'ASIAN_','HISP_'] + + The value is estimated below. + + >>> index = MultiLocalSimpsonConcentration(input_df, groups_list) + >>> index.statistics[0:10] # Values of first 10 units + array([0.84564007, 0.66608405, 0.50090253, 0.8700551 , 0.90194944, + 0.86871822, 0.95552644, 0.9601067 , 0.96276946, 0.88241452]) + + Notes + ----- + Based on the local version of Equation 1 of page 37 of Reardon, Sean F., and Glenn Firebaugh. "Measures of multigroup segregation." Sociological methodology 32.1 (2002): 33-67. + + Simpson's concentration index can be simply interpreted as the probability that two individuals chosen at random and independently from the population will be found to belong to the same group. + + Higher values means lesser segregation. + + Simpson's Concentration + Simpson's Interaction = 1 + + Reference: :cite:`reardon2002measures`. + + """ + +
[docs] def __init__(self, data, groups): + + aux = _multi_local_simpson_concentration(data, groups) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _multi_local_simpson_concentration
+ + +def _local_relative_centralization(data, group_pop_var, total_pop_var, k_neigh = 5): + """ + Calculation of Local Relative Centralization index for each unit + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + k_neigh : integer greater than 0. Default is 5. + Number of assumed neighbors for local context (it uses k-nearest algorithm method) + + Returns + ------- + + statistics : np.array(n) + Local Relative Centralization values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Folch, David C., and Sergio J. Rey. "The centralization index: A measure of local spatial segregation." Papers in Regional Science 95.3 (2016): 555-576. + + Reference: :cite:`folch2016centralization`. + """ + + data = data.copy() + + core_data = data[[group_pop_var, total_pop_var, 'geometry']] + + c_lons = data.centroid.map(lambda p: p.x) + c_lats = data.centroid.map(lambda p: p.y) + + points = list(zip(c_lons, c_lats)) + kd = lps.cg.kdtree.KDTree(np.array(points)) + wnnk = lps.weights.KNN(kd, k = k_neigh) + + local_RCEs = np.empty(len(data)) + + for i in range(len(data)): + + x = list(wnnk.neighbors.values())[i] + x.append(list(wnnk.neighbors.keys())[i]) # Append in the end the current unit i inside the local context + + local_data = data.iloc[x,:].copy() + + # The center is given by the last position (i.e. the current unit i) + local_RCE = RelativeCentralization(local_data, group_pop_var, total_pop_var, center = len(local_data) - 1) + + local_RCEs[i] = local_RCE.statistic + + return local_RCEs, core_data + + +
[docs]class LocalRelativeCentralization: + """ + Calculation of Local Relative Centralization index for each unit + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + k_neigh : integer greater than 0. Default is 5. + Number of assumed neighbors for local context (it uses k-nearest algorithm method) + + Returns + ------- + + statistics : np.array(n) + Local Relative Centralization values for each unit + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we are going to use 2000 Census Tract Data for Sacramento MSA, CA. The group of interest is Black population. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import libpysal + >>> import geopandas as gpd + >>> from segregation.local import LocalRelativeCentralization + + Then, we read the data and create an auxiliary list with only the necessary columns for fitting the index. + + >>> input_df = gpd.read_file(libpysal.examples.get_path("sacramentot2.shp")) + + The value is estimated below. + + >>> index = LocalRelativeCentralization(input_df, 'BLACK_', 'TOT_POP') + >>> index.statistics[0:10] # Values of first 10 units + array([ 0.03443055, -0.29063264, -0.19110976, 0.24978919, 0.01252249, + 0.61152941, 0.78917647, 0.53129412, 0.04436346, -0.20216325]) + + Notes + ----- + Based on Folch, David C., and Sergio J. Rey. "The centralization index: A measure of local spatial segregation." Papers in Regional Science 95.3 (2016): 555-576. + + Reference: :cite:`folch2016centralization`. + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, k_neigh = 5): + + aux = _local_relative_centralization(data, group_pop_var, total_pop_var, k_neigh) + + self.statistics = aux[0] + self.core_data = aux[1] + self._function = _local_relative_centralization
+ + + + + + + +# Deprecation Calls + +msg = _dep_message("Multi_Location_Quotient", "MultiLocationQuotient") +Multi_Location_Quotient = DeprecationHelper(MultiLocationQuotient, message=msg) + +msg = _dep_message("Multi_Local_Diversity", "MultiLocalDiversity") +Multi_Local_Diversity = DeprecationHelper(MultiLocalDiversity, message=msg) + +msg = _dep_message("Multi_Local_Entropy", "MultiLocalEntropy") +Multi_Local_Entropy = DeprecationHelper(MultiLocalEntropy, message=msg) + +msg = _dep_message("Multi_Local_Simpson_Interaction", "MultiLocalSimpsonInteraction") +Multi_Local_Simpson_Interaction = DeprecationHelper(MultiLocalSimpsonInteraction, message=msg) + +msg = _dep_message("Multi_Local_Simpson_Concentration", "MultiLocalSimpsonConcentration") +Multi_Local_Simpson_Concentration = DeprecationHelper(MultiLocalSimpsonConcentration, message=msg) + +msg = _dep_message("Local_Relative_Centralization", "LocalRelativeCentralization") +Local_Relative_Centralization = DeprecationHelper(LocalRelativeCentralization, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/network/network.html b/docs/_modules/segregation/network/network.html new file mode 100644 index 00000000..5dfcc57b --- /dev/null +++ b/docs/_modules/segregation/network/network.html @@ -0,0 +1,273 @@ + + + + + + + segregation.network.network — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.network.network

+"""Calculate street network-based segregation measures."""
+
+__author__ = "Elijah Knaap <elijah.knaap@ucr.edu> Renan X. Cortes <renanc@ucr.edu> and Sergio J. Rey <sergio.rey@ucr.edu>"
+
+import numpy as np
+import pandas as pd
+from warnings import warn
+from segregation.util import project_gdf
+import os
+import sys
+
+
+# This class allows us to hide the diagnostic messages from urbanaccess if the `quiet` flag is set
+class _HiddenPrints:  # from https://stackoverflow.com/questions/8391411/suppress-calls-to-print-python
+    def __enter__(self):
+        self._original_stdout = sys.stdout
+        sys.stdout = open(os.devnull, 'w')
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        sys.stdout.close()
+        sys.stdout = self._original_stdout
+
+
+
[docs]def get_osm_network(geodataframe, maxdist=5000, quiet=True, **kwargs): + """Download a street network from OSM. + + Parameters + ---------- + geodataframe : geopandas.GeoDataFrame + geopandas.GeoDataFrame of the study area. + Coordinate system should be in WGS84 + maxdist : int + Total distance (in meters) of the network queries you may need. + This is used to buffer the network to ensure theres enough to satisfy + your largest query, otherwise there may be edge effects. + quiet: bool + If True, diagnostic messages from urbanaccess will be suppressed + **kwargs : dict + additional kwargs passed through to + urbanaccess.ua_network_from_bbox + + Returns + ------- + pandana.Network + A pandana Network instance for use in accessibility calculations or + spatial segregation measures that include a distance decay + + """ + try: + import pandana as pdna + from urbanaccess.osm.load import ua_network_from_bbox + except ImportError: + raise ImportError( + "You need pandana and urbanaccess to work with segregation's network module\n" + "You can install them with `pip install urbanaccess pandana` " + "or `conda install -c udst pandana urbanaccess`") + + gdf = geodataframe.copy() + gdf = project_gdf(gdf) + gdf = gdf.buffer(maxdist) + bounds = gdf.to_crs(epsg=4326).total_bounds + + if quiet: + print('Downloading data from OSM. This may take awhile.') + with _HiddenPrints(): + net = ua_network_from_bbox(bounds[1], bounds[0], bounds[3], + bounds[2], **kwargs) + else: + net = ua_network_from_bbox(bounds[1], bounds[0], bounds[3], bounds[2], + **kwargs) + print("Building network") + network = pdna.Network(net[0]["x"], net[0]["y"], net[1]["from"], + net[1]["to"], net[1][["distance"]]) + + return network
+ + +
[docs]def calc_access(geodataframe, + network, + distance=2000, + decay="linear", + variables=None, + precompute=True): + """Calculate access to population groups. + + Parameters + ---------- + geodataframe : geopandas.GeoDataFrame + geodataframe with demographic data + network : pandana.Network + pandana.Network instance. This is likely created with `get_osm_network` + or via helper functions from OSMnet or UrbanAccess. + distance : int + maximum distance to consider `accessible` (the default is 2000). + decay : str + decay type pandana should use "linear", "exp", or "flat" + (which means no decay). The default is "linear". + variables : list + list of variable names present on gdf that should be calculated + precompute: bool (default True) + whether pandana should precompute the distance matrix. It can only be + precomputed once, so If you plan to pass the same network to this + function several times, you should set precompute=False for later runs + + Returns + ------- + pandas.DataFrame + DataFrame with two columns, `total_population` and `group_population` + which represent the total number of each group that can be reached + within the supplied `distance` parameter. The DataFrame is indexed + on node_ids + + """ + if precompute: + network.precompute(distance) + + geodataframe["node_ids"] = network.get_node_ids(geodataframe.centroid.x, + geodataframe.centroid.y) + + access = [] + for variable in variables: + network.set(geodataframe.node_ids, + variable=geodataframe[variable], + name=variable) + + access_pop = network.aggregate(distance, + type="sum", + decay=decay, + name=variable) + + access.append(access_pop) + names = ["acc_" + variable for variable in variables] + access = pd.DataFrame(dict(zip(names, access))) + + return access
+
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/docs/_modules/segregation/spatial/spatial_indexes.html b/docs/_modules/segregation/spatial/spatial_indexes.html new file mode 100644 index 00000000..c388dd80 --- /dev/null +++ b/docs/_modules/segregation/spatial/spatial_indexes.html @@ -0,0 +1,3664 @@ + + + + + + + segregation.spatial.spatial_indexes — segregation v1.3.0 Manual + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ +

Source code for segregation.spatial.spatial_indexes

+"""
+Spatial based Segregation Metrics
+"""
+
+__author__ = "Renan X. Cortes <renanc@ucr.edu>, Sergio J. Rey <sergio.rey@ucr.edu> and Elijah Knaap <elijah.knaap@ucr.edu>"
+
+import numpy as np
+import pandas as pd
+import geopandas as gpd
+import warnings
+import libpysal
+
+from libpysal.weights import Queen, Kernel, lag_spatial
+from libpysal.weights.util import fill_diagonal
+from numpy import inf
+from sklearn.metrics.pairwise import manhattan_distances, euclidean_distances, haversine_distances
+from scipy.ndimage.interpolation import shift
+
+from scipy.sparse.csgraph import floyd_warshall
+from scipy.sparse import csr_matrix
+
+from segregation.aspatial.aspatial_indexes import _dissim, MinMax
+from segregation.aspatial.multigroup_aspatial_indexes import MultiInformationTheory, MultiDivergence
+from segregation.network import calc_access
+from libpysal.weights.util import attach_islands
+
+from segregation.util.util import _dep_message, DeprecationHelper, _nan_handle
+
+# Including old and new api in __all__ so users can use both
+
+__all__ = [
+
+    'Spatial_Prox_Prof', 
+    'SpatialProxProf',
+    
+    'Spatial_Dissim', 
+    'SpatialDissim',
+    
+    'Boundary_Spatial_Dissim',
+    'BoundarySpatialDissim',
+    
+    'Perimeter_Area_Ratio_Spatial_Dissim', 
+    'PerimeterAreaRatioSpatialDissim',
+    
+    'SpatialMinMax',
+    
+    'Distance_Decay_Isolation',
+    'DistanceDecayIsolation',
+    
+    'Distance_Decay_Exposure', 
+    'DistanceDecayExposure', 
+    
+    'Spatial_Proximity', 
+    'SpatialProximity',
+    
+    'Absolute_Clustering',
+    'AbsoluteClustering',
+    
+    'Relative_Clustering', 
+    'RelativeClustering', 
+    
+    'Delta', 
+    
+    'Absolute_Concentration',
+    'AbsoluteConcentration',
+    
+    'Relative_Concentration', 
+    'RelativeConcentration', 
+    
+    'Absolute_Centralization',
+    'AbsoluteCentralization',
+    
+    'Relative_Centralization', 
+    'RelativeCentralization', 
+    
+    'SpatialInformationTheory',
+    'SpatialDivergence',
+
+    'compute_segregation_profile'
+]
+
+# The Deprecation calls of the classes are located in the end of this script #
+
+# suppress numpy divide by zero warnings because it occurs a lot during the
+# calculation of many indices
+np.seterr(divide='ignore', invalid='ignore')
+
+
+def _build_local_environment(data, groups, w):
+    """Convert observations into spatially-weighted sums.
+
+    Parameters
+    ----------
+    data : DataFrame
+        dataframe with local observations
+    w : libpysal.weights object
+        weights matrix defining the local environment
+
+    Returns
+    -------
+    DataFrame
+        Spatialized data
+
+    """
+    new_data = []
+    w = fill_diagonal(w)
+    for y in data[groups]:
+        new_data.append(lag_spatial(w, data[y]))
+    new_data = pd.DataFrame(dict(zip(groups, new_data)))
+    return new_data
+
+
+def _return_length_weighted_w(data):
+    """
+    Returns a PySAL weights object that the weights represent the length of the common boundary of two areal units that share border.
+    Author: Levi Wolf <levi.john.wolf@gmail.com>. 
+    Thank you, Levi!
+
+    Parameters
+    ----------
+
+    data          : a geopandas DataFrame with a 'geometry' column.
+
+    Notes
+    -----
+    Currently it's not making any projection.
+
+    """
+
+    w = libpysal.weights.Rook.from_dataframe(
+        data, ids=data.index.tolist(), geom_col=data._geometry_column_name)
+
+    if (len(w.islands) == 0):
+        w = w
+    else:
+        warnings('There are some islands in the GeoDataFrame.')
+        w_aux = libpysal.weights.KNN.from_dataframe(
+            data,
+            ids=data.index.tolist(),
+            geom_col=data._geometry_column_name,
+            k=1)
+        w = attach_islands(w, w_aux)
+
+    adjlist = w.to_adjlist()
+    islands = pd.DataFrame.from_records([{
+        'focal': island,
+        'neighbor': island,
+        'weight': 0
+    } for island in w.islands])
+    merged = adjlist.merge(data.geometry.to_frame('geometry'), left_on='focal',
+                           right_index=True, how='left')\
+                    .merge(data.geometry.to_frame('geometry'), left_on='neighbor',
+                           right_index=True, how='left', suffixes=("_focal", "_neighbor"))\
+
+    # Transforming from pandas to geopandas
+    merged = gpd.GeoDataFrame(merged, geometry='geometry_focal')
+    merged['geometry_neighbor'] = gpd.GeoSeries(merged.geometry_neighbor)
+
+    # Getting the shared boundaries
+    merged['shared_boundary'] = merged.geometry_focal.intersection(
+        merged.set_geometry('geometry_neighbor'))
+
+    # Putting it back to a matrix
+    merged['weight'] = merged.set_geometry('shared_boundary').length
+    merged_with_islands = pd.concat((merged, islands))
+    length_weighted_w = libpysal.weights.W.from_adjlist(
+        merged_with_islands[['focal', 'neighbor', 'weight']])
+    for island in w.islands:
+        length_weighted_w.neighbors[island] = []
+        del length_weighted_w.weights[island]
+
+    length_weighted_w._reset()
+
+    return length_weighted_w
+
+
+def _spatial_prox_profile(data, group_pop_var, total_pop_var, m=1000):
+    """
+    Calculation of Spatial Proximity Profile
+
+    Parameters
+    ----------
+
+    data          : a geopandas DataFrame with a geometry column.
+    
+    group_pop_var : string
+                    The name of variable in data that contains the population size of the group of interest
+                    
+    total_pop_var : string
+                    The name of variable in data that contains the total population of the unit
+                    
+    m             : int
+                    a numeric value indicating the number of thresholds to be used. Default value is 1000. 
+                    A large value of m creates a smoother-looking graph and a more precise spatial proximity profile value but slows down the calculation speed.
+
+    Returns
+    ----------
+
+    statistic : float
+                Spatial Proximity Index
+                
+    core_data : a geopandas DataFrame
+                A geopandas DataFrame that contains the columns used to perform the estimate.
+
+    Notes
+    -----
+    Based on Hong, Seong-Yun, and Yukio Sadahiro. "Measuring geographic segregation: a graph-based approach." Journal of Geographical Systems 16.2 (2014): 211-231.
+    
+    Reference: :cite:`hong2014measuring`.
+
+    """
+
+    if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'):
+        raise TypeError(
+            'data is not a GeoDataFrame and, therefore, this index cannot be calculated.'
+        )
+
+    if ('geometry' not in data.columns):
+        data['geometry'] = data[data._geometry_column_name]
+        data = data.drop([data._geometry_column_name], axis=1)
+        data = data.set_geometry('geometry')
+
+    if (type(m) is not int):
+        raise TypeError('m must be a string.')
+
+    if (m < 2):
+        raise ValueError('m must be greater than 1.')
+
+    if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)):
+        raise TypeError('group_pop_var and total_pop_var must be strings')
+
+    if ((group_pop_var not in data.columns)
+            or (total_pop_var not in data.columns)):
+        raise ValueError(
+            'group_pop_var and total_pop_var must be variables of data')
+
+    data = data.rename(columns={
+        group_pop_var: 'group_pop_var',
+        total_pop_var: 'total_pop_var'
+    })
+
+    if any(data.total_pop_var < data.group_pop_var):
+        raise ValueError(
+            'Group of interest population must equal or lower than the total population of the units.'
+        )
+
+    # Create the shortest distance path between two pair of units using Shimbel matrix. This step was well discussed in https://github.com/pysal/segregation/issues/5.
+    w_libpysal = Queen.from_dataframe(data)
+    graph = csr_matrix(w_libpysal.full()[0])
+    delta = floyd_warshall(csgraph=graph, directed=False)
+
+    def calculate_etat(t):
+        g_t_i = np.where(data.group_pop_var / data.total_pop_var >= t, True,
+                         False)
+        k = g_t_i.sum()
+
+        # i and j only varies in the units subset within the threshold in eta_t of Hong (2014).
+        sub_delta_ij = delta[g_t_i, :][:, g_t_i]
+
+        den = sub_delta_ij.sum()
+        eta_t = (k**2 - k) / den
+        return eta_t
+
+    grid = np.linspace(0, 1, m)
+    aux = np.array(list(map(calculate_etat, grid)))
+    aux[aux == inf] = 0
+    aux[aux == -inf] = 0
+    curve = np.nan_to_num(aux, 0)
+
+    threshold = data.group_pop_var.sum() / data.total_pop_var.sum()
+    SPP = ((threshold - ((curve[grid < threshold]).sum() / m -
+                         (curve[grid >= threshold]).sum() / m)) /
+           (1 - threshold))
+
+    core_data = data[['group_pop_var', 'total_pop_var', 'geometry']]
+
+    return SPP, grid, curve, core_data
+
+
+
[docs]class SpatialProxProf: + """ + Calculation of Spatial Proximity Profile + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + m : int + a numeric value indicating the number of thresholds to be used. Default value is 1000. + A large value of m creates a smoother-looking graph and a more precise spatial proximity profile value but slows down the calculation speed. + + Attributes + ---------- + + statistic : float + Spatial Proximity Profile Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the spatial proximity profile (SPP) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import SpatialProxProf + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + >>> spat_prox_index = SpatialProxProf(gdf, 'nhblk10', 'pop10') + >>> spat_prox_index.statistic + 0.11217269612149207 + + You can plot the profile curve with the plot method. + + >>> spat_prox_index.plot() + + Notes + ----- + Based on Hong, Seong-Yun, and Yukio Sadahiro. "Measuring geographic segregation: a graph-based approach." Journal of Geographical Systems 16.2 (2014): 211-231. + + Reference: :cite:`hong2014measuring`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, m=1000): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _spatial_prox_profile(data, group_pop_var, total_pop_var, m) + + self.statistic = aux[0] + self.grid = aux[1] + self.curve = aux[2] + self.core_data = aux[3] + self._function = _spatial_prox_profile
+ + def plot(self): + """ + Plot the Spatial Proximity Profile + """ + try: + import matplotlib.pyplot as plt + except ImportError: + warnings.warn('This method relies on importing `matplotlib`') + graph = plt.scatter(self.grid, self.curve, s=0.1) + return graph
+ + +def _spatial_dissim(data, + group_pop_var, + total_pop_var, + w=None, + standardize=False): + """ + Calculation of Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + w : W + A PySAL weights object. If not provided, Queen contiguity matrix is used. + + standardize : boolean + A condition for row standardisation of the weights matrices. If True, the values of cij in the formulas gets row standardized. + For the sake of comparison, the seg R package of Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + works by default with row standardization. + + Returns + ---------- + + statistic : float + Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Morrill, R. L. (1991) "On the Measure of Geographic Segregation". Geography Research Forum. + + Reference: :cite:`morrill1991measure`. + + """ + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if (type(standardize) is not bool): + raise TypeError('std is not a boolean object') + + if w is None: + w_object = Queen.from_dataframe(data) + else: + w_object = w + + if (not issubclass(type(w_object), libpysal.weights.W)): + raise TypeError('w is not a PySAL weights object') + + D = _dissim(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + # If a unit has zero population, the group of interest frequency is zero + pi = np.where(t == 0, 0, x / t) + + if not standardize: + cij = w_object.full()[0] + else: + cij = w_object.full()[0] + cij = cij / cij.sum(axis=1).reshape((cij.shape[0], 1)) + + # Inspired in (second solution): https://stackoverflow.com/questions/22720864/efficiently-calculating-a-euclidean-distance-matrix-using-numpy + # Distance Matrix + abs_dist = abs(pi[..., np.newaxis] - pi) + + # manhattan_distances used to compute absolute distances + num = np.multiply(abs_dist, cij).sum() + den = cij.sum() + SD = D - num / den + SD + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return SD, core_data + + +
[docs]class SpatialDissim: + """ + Calculation of Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + w : W + A PySAL weights object. If not provided, Queen contiguity matrix is used. + + standardize : boolean + A condition for row standardisation of the weights matrices. If True, the values of cij in the formulas gets row standardized. + For the sake of comparison, the seg R package of Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + works by default with row standardization. + + Attributes + ---------- + + statistic : float + Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the degree of spatial dissimilarity (D) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. The neighborhood contiguity matrix is used. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import SpatialDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> spatial_dissim_index = SpatialDissim(gdf, 'nhblk10', 'pop10') + >>> spatial_dissim_index.statistic + 0.2864885055405311 + + To use different neighborhood matrices: + + >>> from libpysal.weights import Rook, KNN + + Assuming K-nearest neighbors with k = 4 + + >>> knn = KNN.from_dataframe(gdf, k=4) + >>> spatial_dissim_index = Spatial_Dissim(gdf, 'nhblk10', 'pop10', w = knn) + >>> spatial_dissim_index.statistic + 0.28544347200877285 + + Assuming Rook contiguity neighborhood + + >>> roo = Rook.from_dataframe(gdf) + >>> spatial_dissim_index = Spatial_Dissim(gdf, 'nhblk10', 'pop10', w = roo) + >>> spatial_dissim_index.statistic + 0.2866269198707091 + + Notes + ----- + Based on Morrill, R. L. (1991) "On the Measure of Geographic Segregation". Geography Research Forum. + + Reference: :cite:`morrill1991measure`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + w=None, + standardize=False): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _spatial_dissim(data, group_pop_var, total_pop_var, w, + standardize) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _spatial_dissim
+ + +def _boundary_spatial_dissim(data, + group_pop_var, + total_pop_var, + standardize=False): + """ + Calculation of Boundary Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + standardize : boolean + A condition for row standardisation of the weights matrices. If True, the values of cij in the formulas gets row standardized. + For the sake of comparison, the seg R package of Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + works by default without row standardization. That is, directly with border length. + + Returns + ---------- + + statistic : float + Boundary Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + The formula is based on Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + + Original paper by Wong, David WS. "Spatial indices of segregation." Urban studies 30.3 (1993): 559-572. + + References: :cite:`hong2014implementing` and :cite:`wong1993spatial`. + + """ + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if (type(standardize) is not bool): + raise TypeError('std is not a boolean object') + + D = _dissim(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + # If a unit has zero population, the group of interest frequency is zero + data = data.assign( + pi=np.where(data.total_pop_var == 0, 0, data.group_pop_var / + data.total_pop_var)) + + if not standardize: + cij = _return_length_weighted_w(data).full()[0] + else: + cij = _return_length_weighted_w(data).full()[0] + cij = cij / cij.sum(axis=1).reshape((cij.shape[0], 1)) + + # manhattan_distances used to compute absolute distances + num = np.multiply(manhattan_distances(data[['pi']]), cij).sum() + den = cij.sum() + BSD = D - num / den + BSD + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return BSD, core_data + + +
[docs]class BoundarySpatialDissim: + """ + Calculation of Boundary Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + standardize : boolean + A condition for row standardisation of the weights matrices. If True, the values of cij in the formulas gets row standardized. + For the sake of comparison, the seg R package of Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + works by default without row standardization. That is, directly with border length. + + + Attributes + ---------- + + statistic : float + Boundary Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the degree of boundary spatial dissimilarity (D) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import BoundarySpatialDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> boundary_spatial_dissim_index = BoundarySpatialDissim(gdf, 'nhblk10', 'pop10') + >>> boundary_spatial_dissim_index.statistic + 0.28869903953453163 + + Notes + ----- + The formula is based on Hong, Seong-Yun, David O'Sullivan, and Yukio Sadahiro. "Implementing spatial segregation measures in R." PloS one 9.11 (2014): e113767. + + Original paper by Wong, David WS. "Spatial indices of segregation." Urban studies 30.3 (1993): 559-572. + + References: :cite:`hong2014implementing` and :cite:`wong1993spatial`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, standardize=False): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _boundary_spatial_dissim(data, group_pop_var, total_pop_var, + standardize) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _boundary_spatial_dissim
+ + +def _perimeter_area_ratio_spatial_dissim(data, + group_pop_var, + total_pop_var, + standardize=True): + """ + Calculation of Perimeter/Area Ratio Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + standardize : boolean + A condition for standardisation of the weights matrices. + If True, the values of cij in the formulas gets standardized and the overall sum is 1. + + Returns + ---------- + + statistic : float + Perimeter/Area Ratio Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Originally based on Wong, David WS. "Spatial indices of segregation." Urban studies 30.3 (1993): 559-572. + + However, Tivadar, Mihai. "OasisR: An R Package to Bring Some Order to the World of Segregation Measurement." Journal of Statistical Software 89.1 (2019): 1-39. + points out that in Wong’s original there is an issue with the formula which is an extra division by 2 in the spatial interaction component. + This function follows the formula present in the first Appendix of Tivadar, Mihai. "OasisR: An R Package to Bring Some Order to the World of Segregation Measurement." Journal of Statistical Software 89.1 (2019): 1-39. + + References: :cite:`wong1993spatial` and :cite:`tivadar2019oasisr`. + + """ + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if (type(standardize) is not bool): + raise TypeError('std is not a boolean object') + + D = _dissim(data, group_pop_var, total_pop_var)[0] + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + # If a unit has zero population, the group of interest frequency is zero + data = data.assign( + pi=np.where(data.total_pop_var == 0, 0, data.group_pop_var / + data.total_pop_var)) + + if not standardize: + cij = _return_length_weighted_w(data).full()[0] + else: + cij = _return_length_weighted_w(data).full()[0] + cij = cij / cij.sum() + + peri = data.length + ai = data.area + + aux_sum = np.add( + np.array(list((peri / ai))), + np.array(list((peri / ai))).reshape((len(list((peri / ai))), 1))) + + max_pa = max(peri / ai) + + num = np.multiply(np.multiply(manhattan_distances(data[['pi']]), cij), + aux_sum).sum() + den = 2 * max_pa + + PARD = D - (num / den) + PARD + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return PARD, core_data + + +
[docs]class PerimeterAreaRatioSpatialDissim: + """ + Calculation of Perimeter/Area Ratio Spatial Dissimilarity index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + standardize : boolean + A condition for standardisation of the weights matrices. + If True, the values of cij in the formulas gets standardized and the overall sum is 1. + + Attributes + ---------- + + statistic : float + Perimeter/Area Ratio Spatial Dissimilarity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the degree of perimeter/area ratio spatial dissimilarity (PARD) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import PerimeterAreaRatioSpatialDissim + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> perimeter_area_ratio_spatial_dissim_index = PerimeterAreaRatioSpatialDissim(gdf, 'nhblk10', 'pop10') + >>> perimeter_area_ratio_spatial_dissim_index.statistic + 0.31260876347432687 + + Notes + ----- + Originally based on Wong, David WS. "Spatial indices of segregation." Urban studies 30.3 (1993): 559-572. + + However, Tivadar, Mihai. "OasisR: An R Package to Bring Some Order to the World of Segregation Measurement." Journal of Statistical Software 89.1 (2019): 1-39. + points out that in Wong’s original there is an issue with the formula which is an extra division by 2 in the spatial interaction component. + This function follows the formula present in the first Appendix of Tivadar, Mihai. "OasisR: An R Package to Bring Some Order to the World of Segregation Measurement." Journal of Statistical Software 89.1 (2019): 1-39. + + References: :cite:`wong1993spatial` and :cite:`tivadar2019oasisr`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var, standardize=True): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _perimeter_area_ratio_spatial_dissim(data, group_pop_var, + total_pop_var, standardize) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _perimeter_area_ratio_spatial_dissim
+ + + +
[docs]class SpatialMinMax(MinMax): + """Spatial MinMax Index. + + This class calculates the spatial version of the MinMax + index. The data are "spatialized" by converting each observation + to a "local environment" by creating a weighted sum of the focal unit with + its neighboring observations, where the neighborhood is defined by a + libpysal weights matrix or a pandana Network instance. + + Parameters + ---------- + data : geopandas.GeoDataFrame + geodataframe with + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + total_pop_var : string + The name of variable in data that contains the total population of the unit + w : libpysal.W + distance-based PySAL spatial weights matrix instance + network : pandana.Network + pandana.Network instance. This is likely created with `get_osm_network` + or via helper functions from OSMnet or UrbanAccess. + distance : int + maximum distance to consider `accessible` (the default is 2000). + decay : str + decay type pandana should use "linear", "exp", or "flat" + (which means no decay). The default is "linear". + precompute: bool + Whether the pandana.Network instance should precompute the range + queries.This is true by default, but if you plan to calculate several + indices using the same network, then you can set this + parameter to `False` to avoid precomputing repeatedly inside the + function + + Attributes + ---------- + + statistic : float + SpatialMinMax Index + + core_data : a pandas DataFrame + A pandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on O'Sullivan & Wong (2007). A Surfaceâ€Based Approach to Measuring Spatial Segregation. + Geographical Analysis 39 (2). https://doi.org/10.1111/j.1538-4632.2007.00699.x + + Reference: :cite:`osullivanwong2007surface`. + + We'd like to thank @AnttiHaerkoenen for this contribution! + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + network=None, + w=None, + decay='linear', + distance=2000, + precompute=True): + + data = data.rename(columns={group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var'}) + + data['group_2_pop_var'] = data['total_pop_var'] - data['group_pop_var'] + + groups = ['group_pop_var', 'group_2_pop_var'] + + if w is None and network is None: + points = [(p.x, p.y) for p in data.centroid] + w = Kernel(points) + + if w and network: + raise ( + "must pass either a pandana network or a pysal weights object\ + but not both") + elif network: + df = calc_access(data, + variables=groups, + network=network, + distance=distance, + decay=decay, + precompute=precompute) + groups = ["acc_" + group for group in groups] + else: + df = _build_local_environment(data, groups, w) + + df['resulting_total'] = df['group_pop_var'] + df['group_2_pop_var'] + + super().__init__(df, 'group_pop_var', 'resulting_total')
+ + + +def _distance_decay_isolation(data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + """ + Calculation of Distance Decay Isolation index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + + statistic : float + Distance Decay Isolation Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + It may be interpreted as the probability that the next person a group member meets anywhere in space is from the same group. + + Based on Morgan, Barrie S. "A distance-decay based interaction index to measure residential segregation." Area (1983): 211-217. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`morgan1983distance`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + if (alpha < 0): + raise ValueError('alpha must be greater than zero.') + + if (beta < 0): + raise ValueError('beta must be greater than zero.') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + X = x.sum() + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if (metric == 'euclidean'): + dist = euclidean_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) + + if (metric == 'haversine'): + dist = haversine_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) # This needs to be latitude first! + + c = np.exp(-dist) + + if c.sum() < 10 ** (-15): + raise ValueError('It not possible to determine accurately the exponential of the negative distances. This is probably due to the large magnitude of the centroids numbers. It is recommended to reproject the geopandas DataFrame. Also, if this is a not lat-long CRS, it is recommended to set metric to \'haversine\'') + + np.fill_diagonal(c, val = np.exp(-(alpha * data.area)**(beta))) + + Pij = np.multiply(c, t) / np.sum(np.multiply(c, t), axis=1) + + DDxPx = (np.array(x / X) * + np.nansum(np.multiply(Pij, np.array(x / t)), axis=1)).sum() + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return DDxPx, core_data + + +
[docs]class DistanceDecayIsolation: + """ + Calculation of Distance Decay Isolation index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + + statistic : float + Distance Decay Isolation Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the distance decay isolation index (DDxPx) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import DistanceDecayIsolation + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> spatial_isolation_index = DistanceDecayIsolation(gdf, 'nhblk10', 'pop10') + >>> spatial_isolation_index.statistic + 0.07214112078134231 + + Notes + ----- + It may be interpreted as the probability that the next person a group member meets anywhere in space is from the same group. + + Based on Morgan, Barrie S. "A distance-decay based interaction index to measure residential segregation." Area (1983): 211-217. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`morgan1983distance`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _distance_decay_isolation(data, group_pop_var, total_pop_var, + alpha, beta, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _distance_decay_isolation
+ + +def _distance_decay_exposure(data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + """ + Calculation of Distance Decay Exposure index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + + statistic : float + Distance Decay Exposure Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + It may be interpreted as the probability that the next person a group member meets anywhere in space is from the other group. + + Based on Morgan, Barrie S. "A distance-decay based interaction index to measure residential segregation." Area (1983): 211-217. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`morgan1983distance`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + if (alpha < 0): + raise ValueError('alpha must be greater than zero.') + + if (beta < 0): + raise ValueError('beta must be greater than zero.') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + y = t - x + X = x.sum() + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if (metric == 'euclidean'): + dist = euclidean_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) + + if (metric == 'haversine'): + dist = haversine_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) # This needs to be latitude first! + + c = np.exp(-dist) + + if c.sum() < 10 ** (-15): + raise ValueError('It not possible to determine accurately the exponential of the negative distances. This is probably due to the large magnitude of the centroids numbers. It is recommended to reproject the geopandas DataFrame. Also, if this is a not lat-long CRS, it is recommended to set metric to \'haversine\'') + + np.fill_diagonal(c, val = np.exp(-(alpha * data.area)**(beta))) + + Pij = np.multiply(c, t) / np.sum(np.multiply(c, t), axis=1) + + DDxPy = (x / X * np.nansum(np.multiply(Pij, y / t), axis=1)).sum() + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return DDxPy, core_data + + +
[docs]class DistanceDecayExposure: + """ + Calculation of Distance Decay Exposure index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + + statistic : float + Distance Decay Exposure Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the distance decay exposure index (DDxPy) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import DistanceDecayExposure + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> spatial_exposure_index = DistanceDecayExposure(gdf, 'nhblk10', 'pop10') + >>> spatial_exposure_index.statistic + 0.9605053172501217 + + Notes + ----- + It may be interpreted as the probability that the next person a group member meets anywhere in space is from the other group. + + Based on Morgan, Barrie S. "A distance-decay based interaction index to measure residential segregation." Area (1983): 211-217. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`morgan1983distance`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _distance_decay_exposure(data, group_pop_var, total_pop_var, + alpha, beta, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _distance_decay_exposure
+ + +def _spatial_proximity(data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + """ + Calculation of Spatial Proximity index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + statistic : float + Spatial Proximity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + if (alpha < 0): + raise ValueError('alpha must be greater than zero.') + + if (beta < 0): + raise ValueError('beta must be greater than zero.') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + if any(data.total_pop_var < data.group_pop_var): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + T = data.total_pop_var.sum() + + data = data.assign(xi=data.group_pop_var, + yi=data.total_pop_var - data.group_pop_var, + ti=data.total_pop_var) + + X = data.xi.sum() + Y = data.yi.sum() + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if (metric == 'euclidean'): + dist = euclidean_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) + + if (metric == 'haversine'): + dist = haversine_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) # This needs to be latitude first! + + c = np.exp(-dist) + + if c.sum() < 10 ** (-15): + raise ValueError('It not possible to determine accurately the exponential of the negative distances. This is probably due to the large magnitude of the centroids numbers. It is recommended to reproject the geopandas DataFrame. Also, if this is a not lat-long CRS, it is recommended to set metric to \'haversine\'') + + np.fill_diagonal(c, val = np.exp(-(alpha * data.area)**(beta))) + + Pxx = ((np.array(data.xi) * c).T * np.array(data.xi)).sum() / X**2 + Pyy = ((np.array(data.yi) * c).T * np.array(data.yi)).sum() / Y**2 + Ptt = ((np.array(data.ti) * c).T * np.array(data.ti)).sum() / T**2 + SP = (X * Pxx + Y * Pyy) / (T * Ptt) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return SP, core_data + + +
[docs]class SpatialProximity: + """ + Calculation of Spatial Proximity index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + statistic : float + Spatial Proximity Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the degree of spatial proximity (SP) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import SpatialProximity + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> spatial_prox_index = SpatialProximity(gdf, 'nhblk10', 'pop10') + >>> spatial_prox_index.statistic + 1.002191883006537 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _spatial_proximity(data, group_pop_var, total_pop_var, alpha, + beta, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _spatial_proximity
+ + +def _absolute_clustering(data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + """ + Calculation of Absolute Clustering index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + statistic : float + Absolute Clustering Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + if (alpha < 0): + raise ValueError('alpha must be greater than zero.') + + if (beta < 0): + raise ValueError('beta must be greater than zero.') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + if any(data.total_pop_var < data.group_pop_var): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + data = data.assign(xi=data.group_pop_var, + yi=data.total_pop_var - data.group_pop_var) + + X = data.xi.sum() + + x = np.array(data.xi) + t = np.array(data.total_pop_var) + n = len(data) + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if (metric == 'euclidean'): + dist = euclidean_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) + + if (metric == 'haversine'): + dist = haversine_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) # This needs to be latitude first! + + c = np.exp(-dist) + + if c.sum() < 10 ** (-15): + raise ValueError('It not possible to determine accurately the exponential of the negative distances. This is probably due to the large magnitude of the centroids numbers. It is recommended to reproject the geopandas DataFrame. Also, if this is a not lat-long CRS, it is recommended to set metric to \'haversine\'') + + np.fill_diagonal(c, val = np.exp(-(alpha * data.area)**(beta))) + + ACL = ((((x/X) * (c * x).sum(axis = 1)).sum()) - ((X / n**2) * c.sum())) / \ + ((((x/X) * (c * t).sum(axis = 1)).sum()) - ((X / n**2) * c.sum())) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return ACL, core_data + + +
[docs]class AbsoluteClustering: + """ + Calculation of Absolute Clustering index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + statistic : float + Absolute Clustering Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the absolute clustering measure (ACL) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['trtid10', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'trtid10') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> absolute_clust_index = Absolute_Clustering(gdf, 'nhblk10', 'pop10') + >>> absolute_clust_index.statistic + 0.20979814508119624 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _absolute_clustering(data, group_pop_var, total_pop_var, alpha, + beta, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _absolute_clustering
+ + +def _relative_clustering(data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + """ + Calculation of Relative Clustering index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + statistic : float + Relative Clustering Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + if (alpha < 0): + raise ValueError('alpha must be greater than zero.') + + if (beta < 0): + raise ValueError('beta must be greater than zero.') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + if any(data.total_pop_var < data.group_pop_var): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + data = data.assign(xi=data.group_pop_var, + yi=data.total_pop_var - data.group_pop_var) + + X = data.xi.sum() + Y = data.yi.sum() + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if (metric == 'euclidean'): + dist = euclidean_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) + + if (metric == 'haversine'): + dist = haversine_distances( + pd.DataFrame({ + 'c_lats': c_lats, + 'c_lons': c_lons + })) # This needs to be latitude first! + + c = np.exp(-dist) + + if c.sum() < 10 ** (-15): + raise ValueError('It not possible to determine accurately the exponential of the negative distances. This is probably due to the large magnitude of the centroids numbers. It is recommended to reproject the geopandas DataFrame. Also, if this is a not lat-long CRS, it is recommended to set metric to \'haversine\'') + + np.fill_diagonal(c, val = np.exp(-(alpha * data.area)**(beta))) + + Pxx = ((np.array(data.xi) * c).T * np.array(data.xi)).sum() / X**2 + Pyy = ((np.array(data.yi) * c).T * np.array(data.yi)).sum() / Y**2 + RCL = Pxx / Pyy - 1 + + if np.isnan(RCL): + raise ValueError('It not possible to determine the distance between, at least, one pair of units. This is probably due to the magnitude of the number of the centroids. We recommend to reproject the geopandas DataFrame.') + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return RCL, core_data + + +
[docs]class RelativeClustering: + """ + Calculation of Relative Clustering index + + Parameters + ---------- + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + alpha : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.6 + + beta : float + A parameter that estimates the extent of the proximity within the same unit. Default value is 0.5 + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + statistic : float + Relative Clustering Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the relative clustering measure (RCL) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import RelativeClustering + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> relative_clust_index = RelativeClustering(gdf, 'nhblk10', 'pop10') + >>> relative_clust_index.statistic + 0.12418089857347714 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + The pairwise distance between unit i and itself is (alpha * area_of_unit_i) ^ beta. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + alpha=0.6, + beta=0.5, + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _relative_clustering(data, group_pop_var, total_pop_var, alpha, + beta, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _relative_clustering
+ + +def _delta(data, group_pop_var, total_pop_var): + """ + Calculation of Delta index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Delta Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + area = np.array(data.area) + + X = x.sum() + A = area.sum() + + DEL = 1 / 2 * abs(x / X - area / A).sum() + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return DEL, core_data + + +
[docs]class Delta: + """ + Calculation of Delta index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Delta Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the delta index (D) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import Delta + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> delta_index = Delta(gdf, 'nhblk10', 'pop10') + >>> delta_index.statistic + 0.8367330649317353 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _delta(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _delta
+ + +def _absolute_concentration(data, group_pop_var, total_pop_var): + """ + Calculation of Absolute Concentration index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Absolute Concentration Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + area = np.array(data.area) + + X = x.sum() + T = t.sum() + + # Create the indexes according to the area ordering + des_ind = (-area).argsort() + asc_ind = area.argsort() + + # A discussion about the extraction of n1 and n2 can be found in https://github.com/pysal/segregation/issues/43 + n1 = np.where(((np.cumsum(t[asc_ind]) / T) < X / T) == False)[0][0] + 1 + n2_aux = np.where(((np.cumsum(t[des_ind]) / T) < X / T) == False)[0][0] + 1 + n2 = len(data) - n2_aux + + n = data.shape[0] + T1 = t[asc_ind][0:n1].sum() + T2 = t[asc_ind][n2:n].sum() + + ACO = 1- ((((x[asc_ind] * area[asc_ind] / X).sum()) - ((t[asc_ind] * area[asc_ind] / T1)[0:n1].sum())) / \ + (((t[asc_ind] * area[asc_ind] / T2)[n2:n].sum()) - ((t[asc_ind] * area[asc_ind]/T1)[0:n1].sum()))) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return ACO, core_data + + +
[docs]class AbsoluteConcentration: + """ + Calculation of Absolute Concentration index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Absolute Concentration Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the absolute concentration index (ACO) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import AbsoluteConcentration + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> absolute_concentration_index = AbsoluteConcentration(gdf, 'nhblk10', 'pop10') + >>> absolute_concentration_index.statistic + 0.9577607171503524 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _absolute_concentration(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _absolute_concentration
+ + +def _relative_concentration(data, group_pop_var, total_pop_var): + """ + Calculation of Relative Concentration index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Returns + ---------- + + statistic : float + Relative Concentration Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + area = np.array(data.area) + + y = t - x + + X = x.sum() + Y = y.sum() + T = t.sum() + + # Create the indexes according to the area ordering + des_ind = (-area).argsort() + asc_ind = area.argsort() + + # A discussion about the extraction of n1 and n2 can be found in https://github.com/pysal/segregation/issues/43 + n1 = np.where(((np.cumsum(t[asc_ind]) / T) < X / T) == False)[0][0] + 1 + n2_aux = np.where(((np.cumsum(t[des_ind]) / T) < X / T) == False)[0][0] + 1 + n2 = len(data) - n2_aux + + n = data.shape[0] + T1 = t[asc_ind][0:n1].sum() + T2 = t[asc_ind][n2:n].sum() + + RCO = ((((x[asc_ind] * area[asc_ind] / X).sum()) / ((y[asc_ind] * area[asc_ind] / Y).sum())) - 1) / \ + ((((t[asc_ind] * area[asc_ind])[0:n1].sum() / T1) / ((t[asc_ind] * area[asc_ind])[n2:n].sum() / T2)) - 1) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + return RCO, core_data + + +
[docs]class RelativeConcentration: + """ + Calculation of Relative Concentration index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + Attributes + ---------- + + statistic : float + Relative Concentration Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + Examples + -------- + In this example, we will calculate the relative concentration index (RCO) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import RelativeConcentration + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> relative_concentration_index = RelativeConcentration(gdf, 'nhblk10', 'pop10') + >>> relative_concentration_index.statistic + 0.5204046784837685 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, data, group_pop_var, total_pop_var): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _relative_concentration(data, group_pop_var, total_pop_var) + + self.statistic = aux[0] + self.core_data = aux[1] + self._function = _relative_concentration
+ + +def _absolute_centralization(data, + group_pop_var, + total_pop_var, + center="mean", + metric='euclidean'): + """ + Calculation of Absolute Centralization index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + center : string, two-dimension values (tuple, list, array) or integer. + This defines what is considered to be the center of the spatial context under study. + + If string, this can be set to: + + "mean": the center longitude/latitude is the mean of longitudes/latitudes of all units. + "median": the center longitude/latitude is the median of longitudes/latitudes of all units. + "population_weighted_mean": the center longitude/latitude is the mean of longitudes/latitudes of all units weighted by the total population. + "largest_population": the center longitude/latitude is the centroid of the unit with largest total population. If there is a tie in the maximum population, the mean of all coordinates will be taken. + + If tuple, list or array, this argument should be the coordinates of the desired center assuming longitude as first value and latitude second value. Therefore, in the form (longitude, latitude), if tuple, or [longitude, latitude] if list or numpy array. + + If integer, the center will be the centroid of the polygon from data corresponding to the integer interpreted as index. + For example, if `center = 0` the centroid of the first row of data is used as center, if `center = 1` the second row will be used, and so on. + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + + statistic : float + Absolute Centralization Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + center_values : list + The center, in the form [longitude, latitude], values used for the calculation of the centralization distances. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + A discussion of defining the center in this function can be found in https://github.com/pysal/segregation/issues/18. + + Reference: :cite:`massey1988dimensions`. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + area = np.array(data.area) + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if isinstance(center, str): + if not center in [ + 'mean', 'median', 'population_weighted_mean', + 'largest_population' + ]: + raise ValueError( + 'The center string must one of \'mean\', \'median\', \'population_weighted_mean\', \'largest_population\'' + ) + + if (center == "mean"): + center_lon = c_lons.mean() + center_lat = c_lats.mean() + + if (center == "median"): + center_lon = np.median(c_lons) + center_lat = np.median(c_lats) + + if (center == "population_weighted_mean"): + center_lon = np.average(c_lons, weights=t) + center_lat = np.average(c_lats, weights=t) + + if (center == "largest_population"): + center_lon = c_lons[np.where(t == t.max())].mean() + center_lat = c_lats[np.where(t == t.max())].mean() + + if isinstance(center, tuple) or isinstance(center, list) or isinstance( + center, np.ndarray): + if np.array(center).shape != (2, ): + raise ValueError('The center tuple/list/array must have length 2.') + + center_lon = center[0] + center_lat = center[1] + + if isinstance(center, int): + if (center > len(data) - 1) or (center < 0): + raise ValueError('The center index must by in the range of data.') + + center_lon = data.iloc[[center]].centroid.x.values[0] + center_lat = data.iloc[[center]].centroid.y.values[0] + + X = x.sum() + A = area.sum() + + dlon = c_lons - center_lon + dlat = c_lats - center_lat + + if (metric == 'euclidean'): + center_dist = np.sqrt((dlon)**2 + (dlat)**2) + + if (metric == 'haversine'): + center_dist = 2 * np.arcsin(np.sqrt(np.sin(dlat/2)**2 + np.cos(center_lat) * np.cos(c_lats) * np.sin(dlon/2)**2)) + + if np.isnan(center_dist).sum() > 0: + raise ValueError('It not possible to determine the center distance for, at least, one unit. This is probably due to the magnitude of the number of the centroids. We recommend to reproject the geopandas DataFrame.') + + asc_ind = center_dist.argsort() + + Xi = np.cumsum(x[asc_ind]) / X + Ai = np.cumsum(area[asc_ind]) / A + + ACE = np.nansum(shift(Xi, 1, cval=np.NaN) * Ai) - \ + np.nansum(Xi * shift(Ai, 1, cval=np.NaN)) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + center_values = [center_lon, center_lat] + + return ACE, core_data, center_values + + +
[docs]class AbsoluteCentralization: + """ + Calculation of Absolute Centralization index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + center : string, two-dimension values (tuple, list, array) or integer. + This defines what is considered to be the center of the spatial context under study. + + If string, this can be set to: + + "mean": the center longitude/latitude is the mean of longitudes/latitudes of all units. + "median": the center longitude/latitude is the median of longitudes/latitudes of all units. + "population_weighted_mean": the center longitude/latitude is the mean of longitudes/latitudes of all units weighted by the total population. + "largest_population": the center longitude/latitude is the centroid of the unit with largest total population. If there is a tie in the maximum population, the mean of all coordinates will be taken. + + If tuple, list or array, this argument should be the coordinates of the desired center assuming longitude as first value and latitude second value. Therefore, in the form (longitude, latitude), if tuple, or [longitude, latitude] if list or numpy array. + + If integer, the center will be the centroid of the polygon from data corresponding to the integer interpreted as index. + For example, if `center = 0` the centroid of the first row of data is used as center, if `center = 1` the second row will be used, and so on. + + Attributes + ---------- + + statistic : float + Absolute Centralization Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + center_values : list + The center, in the form [longitude, latitude], values used for the calculation of the centralization distances. + + Examples + -------- + In this example, we will calculate the absolute centralization index (ACE) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import AbsoluteCentralization + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> absolute_centralization_index = AbsoluteCentralization(gdf, 'nhblk10', 'pop10') + >>> absolute_centralization_index.statistic + 0.6416113799795511 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + A discussion of defining the center in this function can be found in https://github.com/pysal/segregation/issues/18. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + center="mean", + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _absolute_centralization(data, group_pop_var, total_pop_var, + center, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self.center_values = aux[2] + self._function = _absolute_centralization
+ + +def _relative_centralization(data, + group_pop_var, + total_pop_var, + center="mean", + metric='euclidean'): + """ + Calculation of Relative Centralization index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + center : string, two-dimension values (tuple, list, array) or integer. + This defines what is considered to be the center of the spatial context under study. + + If string, this can be set to: + + "mean": the center longitude/latitude is the mean of longitudes/latitudes of all units. + "median": the center longitude/latitude is the median of longitudes/latitudes of all units. + "population_weighted_mean": the center longitude/latitude is the mean of longitudes/latitudes of all units weighted by the total population. + "largest_population": the center longitude/latitude is the centroid of the unit with largest total population. If there is a tie in the maximum population, the mean of all coordinates will be taken. + + If tuple, list or array, this argument should be the coordinates of the desired center assuming longitude as first value and latitude second value. Therefore, in the form (longitude, latitude), if tuple, or [longitude, latitude] if list or numpy array. + + If integer, the center will be the centroid of the polygon from data corresponding to the integer interpreted as index. + For example, if `center = 0` the centroid of the first row of data is used as center, if `center = 1` the second row will be used, and so on. + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Returns + ---------- + + statistic : float + Relative Centralization Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + center_values : list + The center, in the form [longitude, latitude], values used for the calculation of the centralization distances. + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + A discussion of defining the center in this function can be found in https://github.com/pysal/segregation/issues/18. + + """ + + if not metric in ['euclidean', 'haversine']: + raise ValueError('metric must one of \'euclidean\', \'haversine\'') + + if (str(type(data)) != '<class \'geopandas.geodataframe.GeoDataFrame\'>'): + raise TypeError( + 'data is not a GeoDataFrame and, therefore, this index cannot be calculated.' + ) + + if ('geometry' not in data.columns): + data['geometry'] = data[data._geometry_column_name] + data = data.drop([data._geometry_column_name], axis=1) + data = data.set_geometry('geometry') + + if ((type(group_pop_var) is not str) or (type(total_pop_var) is not str)): + raise TypeError('group_pop_var and total_pop_var must be strings') + + if ((group_pop_var not in data.columns) + or (total_pop_var not in data.columns)): + raise ValueError( + 'group_pop_var and total_pop_var must be variables of data') + + data = data.rename(columns={ + group_pop_var: 'group_pop_var', + total_pop_var: 'total_pop_var' + }) + + x = np.array(data.group_pop_var) + t = np.array(data.total_pop_var) + + if any(t < x): + raise ValueError( + 'Group of interest population must equal or lower than the total population of the units.' + ) + + y = t - x + + c_lons = np.array(data.centroid.x) + c_lats = np.array(data.centroid.y) + + if isinstance(center, str): + if not center in [ + 'mean', 'median', 'population_weighted_mean', + 'largest_population' + ]: + raise ValueError( + 'The center string must one of \'mean\', \'median\', \'population_weighted_mean\', \'largest_population\'' + ) + + if (center == "mean"): + center_lon = c_lons.mean() + center_lat = c_lats.mean() + + if (center == "median"): + center_lon = np.median(c_lons) + center_lat = np.median(c_lats) + + if (center == "population_weighted_mean"): + center_lon = np.average(c_lons, weights=t) + center_lat = np.average(c_lats, weights=t) + + if (center == "largest_population"): + center_lon = c_lons[np.where(t == t.max())].mean() + center_lat = c_lats[np.where(t == t.max())].mean() + + if isinstance(center, tuple) or isinstance(center, list) or isinstance( + center, np.ndarray): + if np.array(center).shape != (2, ): + raise ValueError('The center tuple/list/array must have length 2.') + + center_lon = center[0] + center_lat = center[1] + + if isinstance(center, int): + if (center > len(data) - 1) or (center < 0): + raise ValueError('The center index must by in the range of data.') + + center_lon = data.iloc[[center]].centroid.x.values[0] + center_lat = data.iloc[[center]].centroid.y.values[0] + + X = x.sum() + Y = y.sum() + + dlon = c_lons - center_lon + dlat = c_lats - center_lat + + if (metric == 'euclidean'): + center_dist = np.sqrt((dlon)**2 + (dlat)**2) + + if (metric == 'haversine'): + center_dist = 2 * np.arcsin( + np.sqrt( + np.sin(dlat / 2)**2 + + np.cos(center_lat) * np.cos(c_lats) * np.sin(dlon / 2)**2)) + + if np.isnan(center_dist).sum() > 0: + raise ValueError('It not possible to determine the center distance for, at least, one unit. This is probably due to the magnitude of the number of the centroids. We recommend to reproject the geopandas DataFrame.') + + asc_ind = center_dist.argsort() + + Xi = np.cumsum(x[asc_ind]) / X + Yi = np.cumsum(y[asc_ind]) / Y + + RCE = np.nansum(shift(Xi, 1, cval=np.NaN) * Yi) - \ + np.nansum(Xi * shift(Yi, 1, cval=np.NaN)) + + core_data = data[['group_pop_var', 'total_pop_var', 'geometry']] + + center_values = [center_lon, center_lat] + + return RCE, core_data, center_values + + +
[docs]class RelativeCentralization: + """ + Calculation of Relative Centralization index + + Parameters + ---------- + + data : a geopandas DataFrame with a geometry column. + + group_pop_var : string + The name of variable in data that contains the population size of the group of interest + + total_pop_var : string + The name of variable in data that contains the total population of the unit + + center : string, two-dimension values (tuple, list, array) or integer. + This defines what is considered to be the center of the spatial context under study. + + If string, this can be set to: + + "mean": the center longitude/latitude is the mean of longitudes/latitudes of all units. + "median": the center longitude/latitude is the median of longitudes/latitudes of all units. + "population_weighted_mean": the center longitude/latitude is the mean of longitudes/latitudes of all units weighted by the total population. + "largest_population": the center longitude/latitude is the centroid of the unit with largest total population. If there is a tie in the maximum population, the mean of all coordinates will be taken. + + If tuple, list or array, this argument should be the coordinates of the desired center assuming longitude as first value and latitude second value. Therefore, in the form (longitude, latitude), if tuple, or [longitude, latitude] if list or numpy array. + + If integer, the center will be the centroid of the polygon from data corresponding to the integer interpreted as index. + For example, if `center = 0` the centroid of the first row of data is used as center, if `center = 1` the second row will be used, and so on. + + metric : string. Can be 'euclidean' or 'haversine'. Default is 'euclidean'. + The metric used for the distance between spatial units. + If the projection of the CRS of the geopandas DataFrame field is in degrees, this should be set to 'haversine'. + + Attributes + ---------- + + statistic : float + Relative Centralization Index + + core_data : a geopandas DataFrame + A geopandas DataFrame that contains the columns used to perform the estimate. + + center_values : list + The center, in the form [longitude, latitude], values used for the calculation of the centralization distances. + + Examples + -------- + In this example, we will calculate the relative centralization index (RCE) for the Riverside County using the census tract data of 2010. + The group of interest is non-hispanic black people which is the variable nhblk10 in the dataset. + + Firstly, we need to perform some import the modules and the respective function. + + >>> import pandas as pd + >>> import geopandas as gpd + >>> import segregation + >>> from segregation.spatial import RelativeCentralization + + Secondly, we need to read the data: + + >>> # This example uses all census data that the user must provide your own copy of the external database. + >>> # A step-by-step procedure for downloading the data can be found here: https://github.com/spatialucr/geosnap/blob/master/examples/01_getting_started.ipynb + >>> # After the user download the LTDB_Std_All_fullcount.zip and extract the files, the filepath might be something like presented below. + >>> filepath = '~/data/LTDB_Std_2010_fullcount.csv' + >>> census_2010 = pd.read_csv(filepath, encoding = "ISO-8859-1", sep = ",") + + Then, we filter only for the desired county (in this case, Riverside County): + + >>> df = census_2010.loc[census_2010.county == "Riverside County"][['tractid', 'pop10','nhblk10']] + + Then, we read the Riverside map data using geopandas (the county id is 06065): + + >>> map_url = 'https://raw.githubusercontent.com/renanxcortes/inequality-segregation-supplementary-files/master/Tracts_grouped_by_County/06065.json' + >>> map_gpd = gpd.read_file(map_url) + + It is necessary to harmonize the data type of the dataset and the geopandas in order to work the merging procedure. + Later, we extract only the columns that will be used. + + >>> map_gpd['INTGEOID10'] = pd.to_numeric(map_gpd["GEOID10"]) + >>> gdf_pre = map_gpd.merge(df, left_on = 'INTGEOID10', right_on = 'tractid') + >>> gdf = gdf_pre[['geometry', 'pop10', 'nhblk10']] + + The value is estimated below. + + >>> relative_centralization_index = RelativeCentralization(gdf, 'nhblk10', 'pop10') + >>> relative_centralization_index.statistic + 0.18550429720565376 + + Notes + ----- + Based on Massey, Douglas S., and Nancy A. Denton. "The dimensions of residential segregation." Social forces 67.2 (1988): 281-315. + + A discussion of defining the center in this function can be found in https://github.com/pysal/segregation/issues/18. + + Reference: :cite:`massey1988dimensions`. + + """ + +
[docs] def __init__(self, + data, + group_pop_var, + total_pop_var, + center="mean", + metric='euclidean'): + + data = _nan_handle(data[[group_pop_var, total_pop_var, data._geometry_column_name]]) + + aux = _relative_centralization(data, group_pop_var, total_pop_var, + center, metric) + + self.statistic = aux[0] + self.core_data = aux[1] + self.center_values = aux[2] + self._function = _relative_centralization
+ + +class SpatialInformationTheory(MultiInformationTheory): + """Spatial Multigroup Information Theory Index. + + This class calculates the spatial version of the multigroup information + theory index. The data are "spatialized" by converting each observation + to a "local environment" by creating a weighted sum of the focal unit with + its neighboring observations, where the neighborhood is defined by a + libpysal weights matrix or a pandana Network instance. + + Parameters + ---------- + data : geopandas.GeoDataFrame + geodataframe with + groups : list + list of columns on gdf representing population groups for which the SIT + index should be calculated + network : pandana.Network + pandana.Network instance. This is likely created with `get_osm_network` + or via helper functions from OSMnet or UrbanAccess. + w : libpysal.W + distance-based PySAL spatial weights matrix instance + distance : int + maximum distance to consider `accessible` (the default is 2000). + decay : str + decay type pandana should use "linear", "exp", or "flat" + (which means no decay). The default is "linear". + precompute: bool + Whether the pandana.Network instance should precompute the range + queries.This is true by default, but if you plan to calculate several + indices using the same network, then you can set this + parameter to `False` to avoid precomputing repeatedly inside the + function + + """ + + def __init__(self, + data, + groups, + network=None, + w=None, + decay='linear', + distance=2000, + precompute=True): + + if w and network: + raise ( + "must pass either a pandana network or a pysal weights object\ + but not both") + elif network: + df = calc_access(data, + variables=groups, + network=network, + distance=distance, + decay=decay, + precompute=precompute) + groups = ["acc_" + group for group in groups] + else: + df = _build_local_environment(data, groups, w) + super().__init__(df, groups) + + +class SpatialDivergence(MultiDivergence): + """Spatial Multigroup Divergence Index. + + This class calculates the spatial version of the multigroup divergence + index. The data are "spatialized" by converting each observation + to a "local environment" by creating a weighted sum of the focal unit with + its neighboring observations, where the neighborhood is defined by a + libpysal weights matrix or a pandana Network instance. + + Parameters + ---------- + data : geopandas.GeoDataFrame + geodataframe with + groups : list + list of columns on gdf representing population groups for which the + divergence index should be calculated + w : libpysal.W + distance-based PySAL spatial weights matrix instance + network : pandana.Network + pandana.Network instance. This is likely created with `get_osm_network` + or via helper functions from OSMnet or UrbanAccess. + distance : int + maximum distance to consider `accessible` (the default is 2000). + decay : str + decay type pandana should use "linear", "exp", or "flat" + (which means no decay). The default is "linear". + precompute: bool + Whether the pandana.Network instance should precompute the range + queries.This is true by default, but if you plan to calculate several + indices using the same network, then you can set this + parameter to `False` to avoid precomputing repeatedly inside the + function + """ + + def __init__(self, + data, + groups, + network=None, + w=None, + decay='linear', + distance=2000, + precompute=True): + + if w and network: + raise ( + "must pass either a pandana network or a pysal weights object\ + but not both") + elif network: + df = calc_access(data, + variables=groups, + network=network, + distance=distance, + decay=decay, + precompute=precompute) + groups = ["acc_" + group for group in groups] + else: + df = _build_local_environment(data, groups, w) + super().__init__(df, groups) + + +def compute_segregation_profile(gdf, + groups=None, + distances=None, + network=None, + decay='linear', + function='triangular', + precompute=True): + """Compute multiscalar segregation profile. + + This function calculates several Spatial Information Theory indices with + increasing distance parameters. + + Parameters + ---------- + gdf : geopandas.GeoDataFrame + geodataframe with rows as observations and columns as population + variables. Note that if using a network distance, the coordinate + system for this gdf should be 4326. If using euclidian distance, + this must be projected into planar coordinates like state plane or UTM. + groups : list + list of variables . + distances : list + list of floats representing bandwidth distances that define a local + environment. + network : pandana.Network (optional) + A pandana.Network likely created with + `segregation.network.get_osm_network`. + decay : str (optional) + decay type to be used in pandana accessibility calculation (the + default is 'linear'). + function: 'str' (optional) + which weighting function should be passed to libpysal.weights.Kernel + must be one of: 'triangular','uniform','quadratic','quartic','gaussian' + precompute: bool + Whether the pandana.Network instance should precompute the range + queries.This is true by default, but if you plan to calculate several + segregation profiles using the same network, then you can set this + parameter to `False` to avoid precomputing repeatedly inside the + function + + Returns + ------- + dict + dictionary with distances as keys and SIT statistics as values + + Notes + ----- + Based on Sean F. Reardon, Stephen A. Matthews, David O’Sullivan, Barrett A. Lee, Glenn Firebaugh, Chad R. Farrell, & Kendra Bischoff. (2008). The Geographic Scale of Metropolitan Racial Segregation. Demography, 45(3), 489–514. https://doi.org/10.1353/dem.0.0019. + + Reference: :cite:`Reardon2008`. + + """ + gdf = gdf.copy() + gdf[groups] = gdf[groups].astype(float) + indices = {} + indices[0] = MultiInformationTheory(gdf, groups).statistic + + if network: + if not gdf.crs.name == 'WGS 84': + gdf = gdf.to_crs(epsg=4326) + groups2 = ['acc_' + group for group in groups] + if precompute: + maxdist = max(distances) + network.precompute(maxdist) + for distance in distances: + distance = np.float(distance) + access = calc_access(gdf, + network, + decay=decay, + variables=groups, + distance=distance, + precompute=False) + sit = MultiInformationTheory(access, groups2) + indices[distance] = sit.statistic + else: + for distance in distances: + w = Kernel.from_dataframe(gdf, + bandwidth=distance, + function=function) + sit = SpatialInformationTheory(gdf, groups, w=w) + indices[distance] = sit.statistic + return indices + + +# Deprecation Calls + +msg = _dep_message("Spatial_Prox_Prof", "SpatialProxProf") +Spatial_Prox_Prof = DeprecationHelper(SpatialProxProf, message=msg) + +msg = _dep_message("Spatial_Dissim", "SpatialDissim") +Spatial_Dissim = DeprecationHelper(SpatialDissim, message=msg) + +msg = _dep_message("Boundary_Spatial_Dissim", "BoundarySpatialDissim") +Boundary_Spatial_Dissim = DeprecationHelper(BoundarySpatialDissim, message=msg) + +msg = _dep_message("Perimeter_Area_Ratio_Spatial_Dissim", + "PerimeterAreaRatioSpatialDissim") +Perimeter_Area_Ratio_Spatial_Dissim = DeprecationHelper( + PerimeterAreaRatioSpatialDissim, message=msg) + +msg = _dep_message("Distance_Decay_Isolation", "DistanceDecayIsolation") +Distance_Decay_Isolation = DeprecationHelper(DistanceDecayIsolation, + message=msg) + +msg = _dep_message("Distance_Decay_Exposure", "DistanceDecayExposure") +Distance_Decay_Exposure = DeprecationHelper(DistanceDecayExposure, message=msg) + +msg = _dep_message("Spatial_Proximity", "SpatialProximity") +Spatial_Proximity = DeprecationHelper(SpatialProximity, message=msg) + +msg = _dep_message("Absolute_Clustering", "AbsoluteClustering") +Absolute_Clustering = DeprecationHelper(AbsoluteClustering, message=msg) + +msg = _dep_message("Relative_Clustering", "RelativeClustering") +Relative_Clustering = DeprecationHelper(RelativeClustering, message=msg) + +msg = _dep_message("Absolute_Concentration", "AbsoluteConcentration") +Absolute_Concentration = DeprecationHelper(AbsoluteConcentration, message=msg) + +msg = _dep_message("Relative_Concentration", "RelativeConcentration") +Relative_Concentration = DeprecationHelper(RelativeConcentration, message=msg) + +msg = _dep_message("Absolute_Centralization", "AbsoluteCentralization") +Absolute_Centralization = DeprecationHelper(AbsoluteCentralization, + message=msg) + +msg = _dep_message("Relative_Centralization", "RelativeCentralization") +Relative_Centralization = DeprecationHelper(RelativeCentralization, message=msg) +
+ +
+ +
+
+ + + \ No newline at end of file diff --git a/doc/api.rst b/docs/_sources/api.rst.txt similarity index 100% rename from doc/api.rst rename to docs/_sources/api.rst.txt diff --git a/doc/generated/segregation.aspatial.Atkinson.rst b/docs/_sources/generated/segregation.aspatial.Atkinson.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.Atkinson.rst rename to docs/_sources/generated/segregation.aspatial.Atkinson.rst.txt diff --git a/doc/generated/segregation.aspatial.BiasCorrectedDissim.rst b/docs/_sources/generated/segregation.aspatial.BiasCorrectedDissim.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.BiasCorrectedDissim.rst rename to docs/_sources/generated/segregation.aspatial.BiasCorrectedDissim.rst.txt diff --git a/doc/generated/segregation.aspatial.ConProf.rst b/docs/_sources/generated/segregation.aspatial.ConProf.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.ConProf.rst rename to docs/_sources/generated/segregation.aspatial.ConProf.rst.txt diff --git a/doc/generated/segregation.aspatial.CorrelationR.rst b/docs/_sources/generated/segregation.aspatial.CorrelationR.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.CorrelationR.rst rename to docs/_sources/generated/segregation.aspatial.CorrelationR.rst.txt diff --git a/doc/generated/segregation.aspatial.DensityCorrectedDissim.rst b/docs/_sources/generated/segregation.aspatial.DensityCorrectedDissim.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.DensityCorrectedDissim.rst rename to docs/_sources/generated/segregation.aspatial.DensityCorrectedDissim.rst.txt diff --git a/doc/generated/segregation.aspatial.Dissim.rst b/docs/_sources/generated/segregation.aspatial.Dissim.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.Dissim.rst rename to docs/_sources/generated/segregation.aspatial.Dissim.rst.txt diff --git a/doc/generated/segregation.aspatial.Entropy.rst b/docs/_sources/generated/segregation.aspatial.Entropy.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.Entropy.rst rename to docs/_sources/generated/segregation.aspatial.Entropy.rst.txt diff --git a/doc/generated/segregation.aspatial.Exposure.rst b/docs/_sources/generated/segregation.aspatial.Exposure.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.Exposure.rst rename to docs/_sources/generated/segregation.aspatial.Exposure.rst.txt diff --git a/doc/generated/segregation.aspatial.GiniSeg.rst b/docs/_sources/generated/segregation.aspatial.GiniSeg.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.GiniSeg.rst rename to docs/_sources/generated/segregation.aspatial.GiniSeg.rst.txt diff --git a/doc/generated/segregation.aspatial.Isolation.rst b/docs/_sources/generated/segregation.aspatial.Isolation.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.Isolation.rst rename to docs/_sources/generated/segregation.aspatial.Isolation.rst.txt diff --git a/docs/_sources/generated/segregation.aspatial.MinMax.rst.txt b/docs/_sources/generated/segregation.aspatial.MinMax.rst.txt new file mode 100644 index 00000000..b5068c2b --- /dev/null +++ b/docs/_sources/generated/segregation.aspatial.MinMax.rst.txt @@ -0,0 +1,22 @@ +segregation.aspatial.MinMax +=========================== + +.. currentmodule:: segregation.aspatial + +.. autoclass:: MinMax + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~MinMax.__init__ + + + + + + \ No newline at end of file diff --git a/doc/generated/segregation.aspatial.ModifiedDissim.rst b/docs/_sources/generated/segregation.aspatial.ModifiedDissim.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.ModifiedDissim.rst rename to docs/_sources/generated/segregation.aspatial.ModifiedDissim.rst.txt diff --git a/doc/generated/segregation.aspatial.ModifiedGiniSeg.rst b/docs/_sources/generated/segregation.aspatial.ModifiedGiniSeg.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.ModifiedGiniSeg.rst rename to docs/_sources/generated/segregation.aspatial.ModifiedGiniSeg.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiDissim.rst b/docs/_sources/generated/segregation.aspatial.MultiDissim.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiDissim.rst rename to docs/_sources/generated/segregation.aspatial.MultiDissim.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiDivergence.rst b/docs/_sources/generated/segregation.aspatial.MultiDivergence.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiDivergence.rst rename to docs/_sources/generated/segregation.aspatial.MultiDivergence.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiDiversity.rst b/docs/_sources/generated/segregation.aspatial.MultiDiversity.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiDiversity.rst rename to docs/_sources/generated/segregation.aspatial.MultiDiversity.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiGiniSeg.rst b/docs/_sources/generated/segregation.aspatial.MultiGiniSeg.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiGiniSeg.rst rename to docs/_sources/generated/segregation.aspatial.MultiGiniSeg.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiInformationTheory.rst b/docs/_sources/generated/segregation.aspatial.MultiInformationTheory.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiInformationTheory.rst rename to docs/_sources/generated/segregation.aspatial.MultiInformationTheory.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiNormalizedExposure.rst b/docs/_sources/generated/segregation.aspatial.MultiNormalizedExposure.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiNormalizedExposure.rst rename to docs/_sources/generated/segregation.aspatial.MultiNormalizedExposure.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiRelativeDiversity.rst b/docs/_sources/generated/segregation.aspatial.MultiRelativeDiversity.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiRelativeDiversity.rst rename to docs/_sources/generated/segregation.aspatial.MultiRelativeDiversity.rst.txt diff --git a/doc/generated/segregation.aspatial.MultiSquaredCoefficientVariation.rst b/docs/_sources/generated/segregation.aspatial.MultiSquaredCoefficientVariation.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.MultiSquaredCoefficientVariation.rst rename to docs/_sources/generated/segregation.aspatial.MultiSquaredCoefficientVariation.rst.txt diff --git a/doc/generated/segregation.aspatial.SimpsonsConcentration.rst b/docs/_sources/generated/segregation.aspatial.SimpsonsConcentration.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.SimpsonsConcentration.rst rename to docs/_sources/generated/segregation.aspatial.SimpsonsConcentration.rst.txt diff --git a/doc/generated/segregation.aspatial.SimpsonsInteraction.rst b/docs/_sources/generated/segregation.aspatial.SimpsonsInteraction.rst.txt similarity index 100% rename from doc/generated/segregation.aspatial.SimpsonsInteraction.rst rename to docs/_sources/generated/segregation.aspatial.SimpsonsInteraction.rst.txt diff --git a/doc/generated/segregation.compute_all.ComputeAllAspatialSegregation.rst b/docs/_sources/generated/segregation.compute_all.ComputeAllAspatialSegregation.rst.txt similarity index 100% rename from doc/generated/segregation.compute_all.ComputeAllAspatialSegregation.rst rename to docs/_sources/generated/segregation.compute_all.ComputeAllAspatialSegregation.rst.txt diff --git a/doc/generated/segregation.compute_all.ComputeAllSegregation.rst b/docs/_sources/generated/segregation.compute_all.ComputeAllSegregation.rst.txt similarity index 100% rename from doc/generated/segregation.compute_all.ComputeAllSegregation.rst rename to docs/_sources/generated/segregation.compute_all.ComputeAllSegregation.rst.txt diff --git a/doc/generated/segregation.compute_all.ComputeAllSpatialSegregation.rst b/docs/_sources/generated/segregation.compute_all.ComputeAllSpatialSegregation.rst.txt similarity index 100% rename from doc/generated/segregation.compute_all.ComputeAllSpatialSegregation.rst rename to docs/_sources/generated/segregation.compute_all.ComputeAllSpatialSegregation.rst.txt diff --git a/doc/generated/segregation.decomposition.DecomposeSegregation.rst b/docs/_sources/generated/segregation.decomposition.DecomposeSegregation.rst.txt similarity index 100% rename from doc/generated/segregation.decomposition.DecomposeSegregation.rst rename to docs/_sources/generated/segregation.decomposition.DecomposeSegregation.rst.txt diff --git a/doc/generated/segregation.inference.SingleValueTest.rst b/docs/_sources/generated/segregation.inference.SingleValueTest.rst.txt similarity index 100% rename from doc/generated/segregation.inference.SingleValueTest.rst rename to docs/_sources/generated/segregation.inference.SingleValueTest.rst.txt diff --git a/doc/generated/segregation.inference.TwoValueTest.rst b/docs/_sources/generated/segregation.inference.TwoValueTest.rst.txt similarity index 100% rename from doc/generated/segregation.inference.TwoValueTest.rst rename to docs/_sources/generated/segregation.inference.TwoValueTest.rst.txt diff --git a/doc/generated/segregation.local.LocalRelativeCentralization.rst b/docs/_sources/generated/segregation.local.LocalRelativeCentralization.rst.txt similarity index 100% rename from doc/generated/segregation.local.LocalRelativeCentralization.rst rename to docs/_sources/generated/segregation.local.LocalRelativeCentralization.rst.txt diff --git a/doc/generated/segregation.local.MultiLocalDiversity.rst b/docs/_sources/generated/segregation.local.MultiLocalDiversity.rst.txt similarity index 100% rename from doc/generated/segregation.local.MultiLocalDiversity.rst rename to docs/_sources/generated/segregation.local.MultiLocalDiversity.rst.txt diff --git a/doc/generated/segregation.local.MultiLocalEntropy.rst b/docs/_sources/generated/segregation.local.MultiLocalEntropy.rst.txt similarity index 100% rename from doc/generated/segregation.local.MultiLocalEntropy.rst rename to docs/_sources/generated/segregation.local.MultiLocalEntropy.rst.txt diff --git a/doc/generated/segregation.local.MultiLocalSimpsonConcentration.rst b/docs/_sources/generated/segregation.local.MultiLocalSimpsonConcentration.rst.txt similarity index 100% rename from doc/generated/segregation.local.MultiLocalSimpsonConcentration.rst rename to docs/_sources/generated/segregation.local.MultiLocalSimpsonConcentration.rst.txt diff --git a/doc/generated/segregation.local.MultiLocalSimpsonInteraction.rst b/docs/_sources/generated/segregation.local.MultiLocalSimpsonInteraction.rst.txt similarity index 100% rename from doc/generated/segregation.local.MultiLocalSimpsonInteraction.rst rename to docs/_sources/generated/segregation.local.MultiLocalSimpsonInteraction.rst.txt diff --git a/doc/generated/segregation.local.MultiLocationQuotient.rst b/docs/_sources/generated/segregation.local.MultiLocationQuotient.rst.txt similarity index 100% rename from doc/generated/segregation.local.MultiLocationQuotient.rst rename to docs/_sources/generated/segregation.local.MultiLocationQuotient.rst.txt diff --git a/docs/_sources/generated/segregation.network.calc_access.rst.txt b/docs/_sources/generated/segregation.network.calc_access.rst.txt new file mode 100644 index 00000000..22fc2013 --- /dev/null +++ b/docs/_sources/generated/segregation.network.calc_access.rst.txt @@ -0,0 +1,6 @@ +segregation.network.calc\_access +================================ + +.. currentmodule:: segregation.network + +.. autofunction:: calc_access \ No newline at end of file diff --git a/doc/generated/segregation.network.get_osm_network.rst b/docs/_sources/generated/segregation.network.get_osm_network.rst.txt similarity index 100% rename from doc/generated/segregation.network.get_osm_network.rst rename to docs/_sources/generated/segregation.network.get_osm_network.rst.txt diff --git a/doc/generated/segregation.spatial.AbsoluteCentralization.rst b/docs/_sources/generated/segregation.spatial.AbsoluteCentralization.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.AbsoluteCentralization.rst rename to docs/_sources/generated/segregation.spatial.AbsoluteCentralization.rst.txt diff --git a/doc/generated/segregation.spatial.AbsoluteClustering.rst b/docs/_sources/generated/segregation.spatial.AbsoluteClustering.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.AbsoluteClustering.rst rename to docs/_sources/generated/segregation.spatial.AbsoluteClustering.rst.txt diff --git a/doc/generated/segregation.spatial.AbsoluteConcentration.rst b/docs/_sources/generated/segregation.spatial.AbsoluteConcentration.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.AbsoluteConcentration.rst rename to docs/_sources/generated/segregation.spatial.AbsoluteConcentration.rst.txt diff --git a/doc/generated/segregation.spatial.BoundarySpatialDissim.rst b/docs/_sources/generated/segregation.spatial.BoundarySpatialDissim.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.BoundarySpatialDissim.rst rename to docs/_sources/generated/segregation.spatial.BoundarySpatialDissim.rst.txt diff --git a/doc/generated/segregation.spatial.Delta.rst b/docs/_sources/generated/segregation.spatial.Delta.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.Delta.rst rename to docs/_sources/generated/segregation.spatial.Delta.rst.txt diff --git a/doc/generated/segregation.spatial.DistanceDecayExposure.rst b/docs/_sources/generated/segregation.spatial.DistanceDecayExposure.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.DistanceDecayExposure.rst rename to docs/_sources/generated/segregation.spatial.DistanceDecayExposure.rst.txt diff --git a/doc/generated/segregation.spatial.DistanceDecayIsolation.rst b/docs/_sources/generated/segregation.spatial.DistanceDecayIsolation.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.DistanceDecayIsolation.rst rename to docs/_sources/generated/segregation.spatial.DistanceDecayIsolation.rst.txt diff --git a/doc/generated/segregation.spatial.PerimeterAreaRatioSpatialDissim.rst b/docs/_sources/generated/segregation.spatial.PerimeterAreaRatioSpatialDissim.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.PerimeterAreaRatioSpatialDissim.rst rename to docs/_sources/generated/segregation.spatial.PerimeterAreaRatioSpatialDissim.rst.txt diff --git a/doc/generated/segregation.spatial.RelativeCentralization.rst b/docs/_sources/generated/segregation.spatial.RelativeCentralization.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.RelativeCentralization.rst rename to docs/_sources/generated/segregation.spatial.RelativeCentralization.rst.txt diff --git a/doc/generated/segregation.spatial.RelativeClustering.rst b/docs/_sources/generated/segregation.spatial.RelativeClustering.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.RelativeClustering.rst rename to docs/_sources/generated/segregation.spatial.RelativeClustering.rst.txt diff --git a/doc/generated/segregation.spatial.RelativeConcentration.rst b/docs/_sources/generated/segregation.spatial.RelativeConcentration.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.RelativeConcentration.rst rename to docs/_sources/generated/segregation.spatial.RelativeConcentration.rst.txt diff --git a/doc/generated/segregation.spatial.SpatialDissim.rst b/docs/_sources/generated/segregation.spatial.SpatialDissim.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.SpatialDissim.rst rename to docs/_sources/generated/segregation.spatial.SpatialDissim.rst.txt diff --git a/docs/_sources/generated/segregation.spatial.SpatialMinMax.rst.txt b/docs/_sources/generated/segregation.spatial.SpatialMinMax.rst.txt new file mode 100644 index 00000000..f948a80a --- /dev/null +++ b/docs/_sources/generated/segregation.spatial.SpatialMinMax.rst.txt @@ -0,0 +1,22 @@ +segregation.spatial.SpatialMinMax +================================= + +.. currentmodule:: segregation.spatial + +.. autoclass:: SpatialMinMax + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~SpatialMinMax.__init__ + + + + + + \ No newline at end of file diff --git a/doc/generated/segregation.spatial.SpatialProxProf.rst b/docs/_sources/generated/segregation.spatial.SpatialProxProf.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.SpatialProxProf.rst rename to docs/_sources/generated/segregation.spatial.SpatialProxProf.rst.txt diff --git a/doc/generated/segregation.spatial.SpatialProximity.rst b/docs/_sources/generated/segregation.spatial.SpatialProximity.rst.txt similarity index 100% rename from doc/generated/segregation.spatial.SpatialProximity.rst rename to docs/_sources/generated/segregation.spatial.SpatialProximity.rst.txt diff --git a/doc/index.rst b/docs/_sources/index.rst.txt similarity index 100% rename from doc/index.rst rename to docs/_sources/index.rst.txt diff --git a/doc/installation.rst b/docs/_sources/installation.rst.txt similarity index 100% rename from doc/installation.rst rename to docs/_sources/installation.rst.txt diff --git a/doc/references.rst b/docs/_sources/references.rst.txt similarity index 100% rename from doc/references.rst rename to docs/_sources/references.rst.txt diff --git a/docs/_static/basic.css b/docs/_static/basic.css new file mode 100644 index 00000000..56f5efc6 --- /dev/null +++ b/docs/_static/basic.css @@ -0,0 +1,835 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, pre, div[class|="highlight"] { + clear: both; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; + overflow-x: auto; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; + overflow-x: auto; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +ol > li:first-child > :first-child, +ul > li:first-child > :first-child { + margin-top: 0px; +} + +ol ol > li:first-child > :first-child, +ol ul > li:first-child > :first-child, +ul ol > li:first-child > :first-child, +ul ul > li:first-child > :first-child { + margin-top: revert; +} + +ol > li:last-child > :last-child, +ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol ol > li:last-child > :last-child, +ol ul > li:last-child > :last-child, +ul ol > li:last-child > :last-child, +ul ul > li:last-child > :last-child { + margin-bottom: revert; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0.5em; + content: ":"; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class^="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +code.descclassname { + background-color: transparent; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.css b/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.css new file mode 100644 index 00000000..09e88ce3 --- /dev/null +++ b/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.css @@ -0,0 +1,1109 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +@-ms-viewport { + width: device-width; +} + +.hidden { + display: none; + visibility: hidden; +} + +.visible-phone { + display: none !important; +} + +.visible-tablet { + display: none !important; +} + +.hidden-desktop { + display: none !important; +} + +.visible-desktop { + display: inherit !important; +} + +@media (min-width: 768px) and (max-width: 979px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important ; + } + .visible-tablet { + display: inherit !important; + } + .hidden-tablet { + display: none !important; + } +} + +@media (max-width: 767px) { + .hidden-desktop { + display: inherit !important; + } + .visible-desktop { + display: none !important; + } + .visible-phone { + display: inherit !important; + } + .hidden-phone { + display: none !important; + } +} + +.visible-print { + display: none !important; +} + +@media print { + .visible-print { + display: inherit !important; + } + .hidden-print { + display: none !important; + } +} + +@media (min-width: 1200px) { + .row { + margin-left: -30px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 30px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 1170px; + } + .span12 { + width: 1170px; + } + .span11 { + width: 1070px; + } + .span10 { + width: 970px; + } + .span9 { + width: 870px; + } + .span8 { + width: 770px; + } + .span7 { + width: 670px; + } + .span6 { + width: 570px; + } + .span5 { + width: 470px; + } + .span4 { + width: 370px; + } + .span3 { + width: 270px; + } + .span2 { + width: 170px; + } + .span1 { + width: 70px; + } + .offset12 { + margin-left: 1230px; + } + .offset11 { + margin-left: 1130px; + } + .offset10 { + margin-left: 1030px; + } + .offset9 { + margin-left: 930px; + } + .offset8 { + margin-left: 830px; + } + .offset7 { + margin-left: 730px; + } + .offset6 { + margin-left: 630px; + } + .offset5 { + margin-left: 530px; + } + .offset4 { + margin-left: 430px; + } + .offset3 { + margin-left: 330px; + } + .offset2 { + margin-left: 230px; + } + .offset1 { + margin-left: 130px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.564102564102564%; + *margin-left: 2.5109110747408616%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.564102564102564%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.45299145299145%; + *width: 91.39979996362975%; + } + .row-fluid .span10 { + width: 82.90598290598291%; + *width: 82.8527914166212%; + } + .row-fluid .span9 { + width: 74.35897435897436%; + *width: 74.30578286961266%; + } + .row-fluid .span8 { + width: 65.81196581196582%; + *width: 65.75877432260411%; + } + .row-fluid .span7 { + width: 57.26495726495726%; + *width: 57.21176577559556%; + } + .row-fluid .span6 { + width: 48.717948717948715%; + *width: 48.664757228587014%; + } + .row-fluid .span5 { + width: 40.17094017094017%; + *width: 40.11774868157847%; + } + .row-fluid .span4 { + width: 31.623931623931625%; + *width: 31.570740134569924%; + } + .row-fluid .span3 { + width: 23.076923076923077%; + *width: 23.023731587561375%; + } + .row-fluid .span2 { + width: 14.52991452991453%; + *width: 14.476723040552828%; + } + .row-fluid .span1 { + width: 5.982905982905983%; + *width: 5.929714493544281%; + } + .row-fluid .offset12 { + margin-left: 105.12820512820512%; + *margin-left: 105.02182214948171%; + } + .row-fluid .offset12:first-child { + margin-left: 102.56410256410257%; + *margin-left: 102.45771958537915%; + } + .row-fluid .offset11 { + margin-left: 96.58119658119658%; + *margin-left: 96.47481360247316%; + } + .row-fluid .offset11:first-child { + margin-left: 94.01709401709402%; + *margin-left: 93.91071103837061%; + } + .row-fluid .offset10 { + margin-left: 88.03418803418803%; + *margin-left: 87.92780505546462%; + } + .row-fluid .offset10:first-child { + margin-left: 85.47008547008548%; + *margin-left: 85.36370249136206%; + } + .row-fluid .offset9 { + margin-left: 79.48717948717949%; + *margin-left: 79.38079650845607%; + } + .row-fluid .offset9:first-child { + margin-left: 76.92307692307693%; + *margin-left: 76.81669394435352%; + } + .row-fluid .offset8 { + margin-left: 70.94017094017094%; + *margin-left: 70.83378796144753%; + } + .row-fluid .offset8:first-child { + margin-left: 68.37606837606839%; + *margin-left: 68.26968539734497%; + } + .row-fluid .offset7 { + margin-left: 62.393162393162385%; + *margin-left: 62.28677941443899%; + } + .row-fluid .offset7:first-child { + margin-left: 59.82905982905982%; + *margin-left: 59.72267685033642%; + } + .row-fluid .offset6 { + margin-left: 53.84615384615384%; + *margin-left: 53.739770867430444%; + } + .row-fluid .offset6:first-child { + margin-left: 51.28205128205128%; + *margin-left: 51.175668303327875%; + } + .row-fluid .offset5 { + margin-left: 45.299145299145295%; + *margin-left: 45.1927623204219%; + } + .row-fluid .offset5:first-child { + margin-left: 42.73504273504273%; + *margin-left: 42.62865975631933%; + } + .row-fluid .offset4 { + margin-left: 36.75213675213675%; + *margin-left: 36.645753773413354%; + } + .row-fluid .offset4:first-child { + margin-left: 34.18803418803419%; + *margin-left: 34.081651209310785%; + } + .row-fluid .offset3 { + margin-left: 28.205128205128204%; + *margin-left: 28.0987452264048%; + } + .row-fluid .offset3:first-child { + margin-left: 25.641025641025642%; + *margin-left: 25.53464266230224%; + } + .row-fluid .offset2 { + margin-left: 19.65811965811966%; + *margin-left: 19.551736679396257%; + } + .row-fluid .offset2:first-child { + margin-left: 17.094017094017094%; + *margin-left: 16.98763411529369%; + } + .row-fluid .offset1 { + margin-left: 11.11111111111111%; + *margin-left: 11.004728132387708%; + } + .row-fluid .offset1:first-child { + margin-left: 8.547008547008547%; + *margin-left: 8.440625568285142%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 30px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 1156px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 1056px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 956px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 856px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 756px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 656px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 556px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 456px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 356px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 256px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 156px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 56px; + } + .thumbnails { + margin-left: -30px; + } + .thumbnails > li { + margin-left: 30px; + } + .row-fluid .thumbnails { + margin-left: 0; + } +} + +@media (min-width: 768px) and (max-width: 979px) { + .row { + margin-left: -20px; + *zoom: 1; + } + .row:before, + .row:after { + display: table; + line-height: 0; + content: ""; + } + .row:after { + clear: both; + } + [class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; + } + .container, + .navbar-static-top .container, + .navbar-fixed-top .container, + .navbar-fixed-bottom .container { + width: 724px; + } + .span12 { + width: 724px; + } + .span11 { + width: 662px; + } + .span10 { + width: 600px; + } + .span9 { + width: 538px; + } + .span8 { + width: 476px; + } + .span7 { + width: 414px; + } + .span6 { + width: 352px; + } + .span5 { + width: 290px; + } + .span4 { + width: 228px; + } + .span3 { + width: 166px; + } + .span2 { + width: 104px; + } + .span1 { + width: 42px; + } + .offset12 { + margin-left: 764px; + } + .offset11 { + margin-left: 702px; + } + .offset10 { + margin-left: 640px; + } + .offset9 { + margin-left: 578px; + } + .offset8 { + margin-left: 516px; + } + .offset7 { + margin-left: 454px; + } + .offset6 { + margin-left: 392px; + } + .offset5 { + margin-left: 330px; + } + .offset4 { + margin-left: 268px; + } + .offset3 { + margin-left: 206px; + } + .offset2 { + margin-left: 144px; + } + .offset1 { + margin-left: 82px; + } + .row-fluid { + width: 100%; + *zoom: 1; + } + .row-fluid:before, + .row-fluid:after { + display: table; + line-height: 0; + content: ""; + } + .row-fluid:after { + clear: both; + } + .row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.7624309392265194%; + *margin-left: 2.709239449864817%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="span"]:first-child { + margin-left: 0; + } + .row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.7624309392265194%; + } + .row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; + } + .row-fluid .span11 { + width: 91.43646408839778%; + *width: 91.38327259903608%; + } + .row-fluid .span10 { + width: 82.87292817679558%; + *width: 82.81973668743387%; + } + .row-fluid .span9 { + width: 74.30939226519337%; + *width: 74.25620077583166%; + } + .row-fluid .span8 { + width: 65.74585635359117%; + *width: 65.69266486422946%; + } + .row-fluid .span7 { + width: 57.18232044198895%; + *width: 57.12912895262725%; + } + .row-fluid .span6 { + width: 48.61878453038674%; + *width: 48.56559304102504%; + } + .row-fluid .span5 { + width: 40.05524861878453%; + *width: 40.00205712942283%; + } + .row-fluid .span4 { + width: 31.491712707182323%; + *width: 31.43852121782062%; + } + .row-fluid .span3 { + width: 22.92817679558011%; + *width: 22.87498530621841%; + } + .row-fluid .span2 { + width: 14.3646408839779%; + *width: 14.311449394616199%; + } + .row-fluid .span1 { + width: 5.801104972375691%; + *width: 5.747913483013988%; + } + .row-fluid .offset12 { + margin-left: 105.52486187845304%; + *margin-left: 105.41847889972962%; + } + .row-fluid .offset12:first-child { + margin-left: 102.76243093922652%; + *margin-left: 102.6560479605031%; + } + .row-fluid .offset11 { + margin-left: 96.96132596685082%; + *margin-left: 96.8549429881274%; + } + .row-fluid .offset11:first-child { + margin-left: 94.1988950276243%; + *margin-left: 94.09251204890089%; + } + .row-fluid .offset10 { + margin-left: 88.39779005524862%; + *margin-left: 88.2914070765252%; + } + .row-fluid .offset10:first-child { + margin-left: 85.6353591160221%; + *margin-left: 85.52897613729868%; + } + .row-fluid .offset9 { + margin-left: 79.8342541436464%; + *margin-left: 79.72787116492299%; + } + .row-fluid .offset9:first-child { + margin-left: 77.07182320441989%; + *margin-left: 76.96544022569647%; + } + .row-fluid .offset8 { + margin-left: 71.2707182320442%; + *margin-left: 71.16433525332079%; + } + .row-fluid .offset8:first-child { + margin-left: 68.50828729281768%; + *margin-left: 68.40190431409427%; + } + .row-fluid .offset7 { + margin-left: 62.70718232044199%; + *margin-left: 62.600799341718584%; + } + .row-fluid .offset7:first-child { + margin-left: 59.94475138121547%; + *margin-left: 59.838368402492065%; + } + .row-fluid .offset6 { + margin-left: 54.14364640883978%; + *margin-left: 54.037263430116376%; + } + .row-fluid .offset6:first-child { + margin-left: 51.38121546961326%; + *margin-left: 51.27483249088986%; + } + .row-fluid .offset5 { + margin-left: 45.58011049723757%; + *margin-left: 45.47372751851417%; + } + .row-fluid .offset5:first-child { + margin-left: 42.81767955801105%; + *margin-left: 42.71129657928765%; + } + .row-fluid .offset4 { + margin-left: 37.01657458563536%; + *margin-left: 36.91019160691196%; + } + .row-fluid .offset4:first-child { + margin-left: 34.25414364640884%; + *margin-left: 34.14776066768544%; + } + .row-fluid .offset3 { + margin-left: 28.45303867403315%; + *margin-left: 28.346655695309746%; + } + .row-fluid .offset3:first-child { + margin-left: 25.69060773480663%; + *margin-left: 25.584224756083227%; + } + .row-fluid .offset2 { + margin-left: 19.88950276243094%; + *margin-left: 19.783119783707537%; + } + .row-fluid .offset2:first-child { + margin-left: 17.12707182320442%; + *margin-left: 17.02068884448102%; + } + .row-fluid .offset1 { + margin-left: 11.32596685082873%; + *margin-left: 11.219583872105325%; + } + .row-fluid .offset1:first-child { + margin-left: 8.56353591160221%; + *margin-left: 8.457152932878806%; + } + input, + textarea, + .uneditable-input { + margin-left: 0; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; + } + input.span12, + textarea.span12, + .uneditable-input.span12 { + width: 710px; + } + input.span11, + textarea.span11, + .uneditable-input.span11 { + width: 648px; + } + input.span10, + textarea.span10, + .uneditable-input.span10 { + width: 586px; + } + input.span9, + textarea.span9, + .uneditable-input.span9 { + width: 524px; + } + input.span8, + textarea.span8, + .uneditable-input.span8 { + width: 462px; + } + input.span7, + textarea.span7, + .uneditable-input.span7 { + width: 400px; + } + input.span6, + textarea.span6, + .uneditable-input.span6 { + width: 338px; + } + input.span5, + textarea.span5, + .uneditable-input.span5 { + width: 276px; + } + input.span4, + textarea.span4, + .uneditable-input.span4 { + width: 214px; + } + input.span3, + textarea.span3, + .uneditable-input.span3 { + width: 152px; + } + input.span2, + textarea.span2, + .uneditable-input.span2 { + width: 90px; + } + input.span1, + textarea.span1, + .uneditable-input.span1 { + width: 28px; + } +} + +@media (max-width: 767px) { + body { + padding-right: 20px; + padding-left: 20px; + } + .navbar-fixed-top, + .navbar-fixed-bottom, + .navbar-static-top { + margin-right: -20px; + margin-left: -20px; + } + .container-fluid { + padding: 0; + } + .dl-horizontal dt { + float: none; + width: auto; + clear: none; + text-align: left; + } + .dl-horizontal dd { + margin-left: 0; + } + .container { + width: auto; + } + .row-fluid { + width: 100%; + } + .row, + .thumbnails { + margin-left: 0; + } + .thumbnails > li { + float: none; + margin-left: 0; + } + [class*="span"], + .uneditable-input[class*="span"], + .row-fluid [class*="span"] { + display: block; + float: none; + width: 100%; + margin-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .span12, + .row-fluid .span12 { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .row-fluid [class*="offset"]:first-child { + margin-left: 0; + } + .input-large, + .input-xlarge, + .input-xxlarge, + input[class*="span"], + select[class*="span"], + textarea[class*="span"], + .uneditable-input { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + .input-prepend input, + .input-append input, + .input-prepend input[class*="span"], + .input-append input[class*="span"] { + display: inline-block; + width: auto; + } + .controls-row [class*="span"] + [class*="span"] { + margin-left: 0; + } + .modal { + position: fixed; + top: 20px; + right: 20px; + left: 20px; + width: auto; + margin: 0; + } + .modal.fade { + top: -100px; + } + .modal.fade.in { + top: 20px; + } +} + +@media (max-width: 480px) { + .nav-collapse { + -webkit-transform: translate3d(0, 0, 0); + } + .page-header h1 small { + display: block; + line-height: 20px; + } + input[type="checkbox"], + input[type="radio"] { + border: 1px solid #ccc; + } + .form-horizontal .control-label { + float: none; + width: auto; + padding-top: 0; + text-align: left; + } + .form-horizontal .controls { + margin-left: 0; + } + .form-horizontal .control-list { + padding-top: 0; + } + .form-horizontal .form-actions { + padding-right: 10px; + padding-left: 10px; + } + .media .pull-left, + .media .pull-right { + display: block; + float: none; + margin-bottom: 10px; + } + .media-object { + margin-right: 0; + margin-left: 0; + } + .modal { + top: 10px; + right: 10px; + left: 10px; + } + .modal-header .close { + padding: 10px; + margin: -10px; + } + .carousel-caption { + position: static; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } + .navbar-fixed-top, + .navbar-fixed-bottom { + position: static; + } + .navbar-fixed-top { + margin-bottom: 20px; + } + .navbar-fixed-bottom { + margin-top: 20px; + } + .navbar-fixed-top .navbar-inner, + .navbar-fixed-bottom .navbar-inner { + padding: 5px; + } + .navbar .container { + width: auto; + padding: 0; + } + .navbar .brand { + padding-right: 10px; + padding-left: 10px; + margin: 0 0 0 -5px; + } + .nav-collapse { + clear: both; + } + .nav-collapse .nav { + float: none; + margin: 0 0 10px; + } + .nav-collapse .nav > li { + float: none; + } + .nav-collapse .nav > li > a { + margin-bottom: 2px; + } + .nav-collapse .nav > .divider-vertical { + display: none; + } + .nav-collapse .nav .nav-header { + color: #777777; + text-shadow: none; + } + .nav-collapse .nav > li > a, + .nav-collapse .dropdown-menu a { + padding: 9px 15px; + font-weight: bold; + color: #777777; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; + } + .nav-collapse .btn { + padding: 4px 10px 4px; + font-weight: normal; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + } + .nav-collapse .dropdown-menu li + li a { + margin-bottom: 2px; + } + .nav-collapse .nav > li > a:hover, + .nav-collapse .nav > li > a:focus, + .nav-collapse .dropdown-menu a:hover, + .nav-collapse .dropdown-menu a:focus { + background-color: #f2f2f2; + } + .navbar-inverse .nav-collapse .nav > li > a, + .navbar-inverse .nav-collapse .dropdown-menu a { + color: #999999; + } + .navbar-inverse .nav-collapse .nav > li > a:hover, + .navbar-inverse .nav-collapse .nav > li > a:focus, + .navbar-inverse .nav-collapse .dropdown-menu a:hover, + .navbar-inverse .nav-collapse .dropdown-menu a:focus { + background-color: #111111; + } + .nav-collapse.in .btn-group { + padding: 0; + margin-top: 5px; + } + .nav-collapse .dropdown-menu { + position: static; + top: auto; + left: auto; + display: none; + float: none; + max-width: none; + padding: 0; + margin: 0 15px; + background-color: transparent; + border: none; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; + } + .nav-collapse .open > .dropdown-menu { + display: block; + } + .nav-collapse .dropdown-menu:before, + .nav-collapse .dropdown-menu:after { + display: none; + } + .nav-collapse .dropdown-menu .divider { + display: none; + } + .nav-collapse .nav > li > .dropdown-menu:before, + .nav-collapse .nav > li > .dropdown-menu:after { + display: none; + } + .nav-collapse .navbar-form, + .nav-collapse .navbar-search { + float: none; + padding: 10px 15px; + margin: 10px 0; + border-top: 1px solid #f2f2f2; + border-bottom: 1px solid #f2f2f2; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.1); + } + .navbar-inverse .nav-collapse .navbar-form, + .navbar-inverse .nav-collapse .navbar-search { + border-top-color: #111111; + border-bottom-color: #111111; + } + .navbar .nav-collapse .nav.pull-right { + float: none; + margin-left: 0; + } + .nav-collapse, + .nav-collapse.collapse { + height: 0; + overflow: hidden; + } + .navbar .btn-navbar { + display: block; + } + .navbar-static .navbar-inner { + padding-right: 10px; + padding-left: 10px; + } +} + +@media (min-width: 980px) { + .nav-collapse.collapse { + height: auto !important; + overflow: visible !important; + } +} diff --git a/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css b/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css new file mode 100644 index 00000000..f4ede63f --- /dev/null +++ b/docs/_static/bootstrap-2.3.2/css/bootstrap-responsive.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap Responsive v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@-ms-viewport{width:device-width}.hidden{display:none;visibility:hidden}.visible-phone{display:none!important}.visible-tablet{display:none!important}.hidden-desktop{display:none!important}.visible-desktop{display:inherit!important}@media(min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-tablet{display:inherit!important}.hidden-tablet{display:none!important}}@media(max-width:767px){.hidden-desktop{display:inherit!important}.visible-desktop{display:none!important}.visible-phone{display:inherit!important}.hidden-phone{display:none!important}}.visible-print{display:none!important}@media print{.visible-print{display:inherit!important}.hidden-print{display:none!important}}@media(min-width:1200px){.row{margin-left:-30px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:30px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px}.span12{width:1170px}.span11{width:1070px}.span10{width:970px}.span9{width:870px}.span8{width:770px}.span7{width:670px}.span6{width:570px}.span5{width:470px}.span4{width:370px}.span3{width:270px}.span2{width:170px}.span1{width:70px}.offset12{margin-left:1230px}.offset11{margin-left:1130px}.offset10{margin-left:1030px}.offset9{margin-left:930px}.offset8{margin-left:830px}.offset7{margin-left:730px}.offset6{margin-left:630px}.offset5{margin-left:530px}.offset4{margin-left:430px}.offset3{margin-left:330px}.offset2{margin-left:230px}.offset1{margin-left:130px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%}.row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%}.row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%}.row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%}.row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%}.row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%}.row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%}.row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%}.row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%}.row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%}.row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%}.row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%}.row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%}.row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%}.row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%}.row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%}.row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%}.row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%}.row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%}.row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%}.row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%}.row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%}.row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%}.row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%}.row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%}.row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%}.row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%}.row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%}.row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%}.row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%}.row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%}.row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%}.row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%}.row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%}.row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:30px}input.span12,textarea.span12,.uneditable-input.span12{width:1156px}input.span11,textarea.span11,.uneditable-input.span11{width:1056px}input.span10,textarea.span10,.uneditable-input.span10{width:956px}input.span9,textarea.span9,.uneditable-input.span9{width:856px}input.span8,textarea.span8,.uneditable-input.span8{width:756px}input.span7,textarea.span7,.uneditable-input.span7{width:656px}input.span6,textarea.span6,.uneditable-input.span6{width:556px}input.span5,textarea.span5,.uneditable-input.span5{width:456px}input.span4,textarea.span4,.uneditable-input.span4{width:356px}input.span3,textarea.span3,.uneditable-input.span3{width:256px}input.span2,textarea.span2,.uneditable-input.span2{width:156px}input.span1,textarea.span1,.uneditable-input.span1{width:56px}.thumbnails{margin-left:-30px}.thumbnails>li{margin-left:30px}.row-fluid .thumbnails{margin-left:0}}@media(min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px}.span12{width:724px}.span11{width:662px}.span10{width:600px}.span9{width:538px}.span8{width:476px}.span7{width:414px}.span6{width:352px}.span5{width:290px}.span4{width:228px}.span3{width:166px}.span2{width:104px}.span1{width:42px}.offset12{margin-left:764px}.offset11{margin-left:702px}.offset10{margin-left:640px}.offset9{margin-left:578px}.offset8{margin-left:516px}.offset7{margin-left:454px}.offset6{margin-left:392px}.offset5{margin-left:330px}.offset4{margin-left:268px}.offset3{margin-left:206px}.offset2{margin-left:144px}.offset1{margin-left:82px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%}.row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%}.row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%}.row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%}.row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%}.row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%}.row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%}.row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%}.row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%}.row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%}.row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%}.row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%}.row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%}.row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%}.row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%}.row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%}.row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%}.row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%}.row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%}.row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%}.row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%}.row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%}.row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%}.row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%}.row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%}.row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%}.row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%}.row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%}.row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%}.row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%}.row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%}.row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%}.row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%}.row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%}.row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:710px}input.span11,textarea.span11,.uneditable-input.span11{width:648px}input.span10,textarea.span10,.uneditable-input.span10{width:586px}input.span9,textarea.span9,.uneditable-input.span9{width:524px}input.span8,textarea.span8,.uneditable-input.span8{width:462px}input.span7,textarea.span7,.uneditable-input.span7{width:400px}input.span6,textarea.span6,.uneditable-input.span6{width:338px}input.span5,textarea.span5,.uneditable-input.span5{width:276px}input.span4,textarea.span4,.uneditable-input.span4{width:214px}input.span3,textarea.span3,.uneditable-input.span3{width:152px}input.span2,textarea.span2,.uneditable-input.span2{width:90px}input.span1,textarea.span1,.uneditable-input.span1{width:28px}}@media(max-width:767px){body{padding-right:20px;padding-left:20px}.navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-right:-20px;margin-left:-20px}.container-fluid{padding:0}.dl-horizontal dt{float:none;width:auto;clear:none;text-align:left}.dl-horizontal dd{margin-left:0}.container{width:auto}.row-fluid{width:100%}.row,.thumbnails{margin-left:0}.thumbnails>li{float:none;margin-left:0}[class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{display:block;float:none;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="offset"]:first-child{margin-left:0}.input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto}.controls-row [class*="span"]+[class*="span"]{margin-left:0}.modal{position:fixed;top:20px;right:20px;left:20px;width:auto;margin:0}.modal.fade{top:-100px}.modal.fade.in{top:20px}}@media(max-width:480px){.nav-collapse{-webkit-transform:translate3d(0,0,0)}.page-header h1 small{display:block;line-height:20px}input[type="checkbox"],input[type="radio"]{border:1px solid #ccc}.form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left}.form-horizontal .controls{margin-left:0}.form-horizontal .control-list{padding-top:0}.form-horizontal .form-actions{padding-right:10px;padding-left:10px}.media .pull-left,.media .pull-right{display:block;float:none;margin-bottom:10px}.media-object{margin-right:0;margin-left:0}.modal{top:10px;right:10px;left:10px}.modal-header .close{padding:10px;margin:-10px}.carousel-caption{position:static}}@media(max-width:979px){body{padding-top:0}.navbar-fixed-top,.navbar-fixed-bottom{position:static}.navbar-fixed-top{margin-bottom:20px}.navbar-fixed-bottom{margin-top:20px}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px}.navbar .container{width:auto;padding:0}.navbar .brand{padding-right:10px;padding-left:10px;margin:0 0 0 -5px}.nav-collapse{clear:both}.nav-collapse .nav{float:none;margin:0 0 10px}.nav-collapse .nav>li{float:none}.nav-collapse .nav>li>a{margin-bottom:2px}.nav-collapse .nav>.divider-vertical{display:none}.nav-collapse .nav .nav-header{color:#777;text-shadow:none}.nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.nav-collapse .dropdown-menu li+li a{margin-bottom:2px}.nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2}.navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999}.navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111}.nav-collapse.in .btn-group{padding:0;margin-top:5px}.nav-collapse .dropdown-menu{position:static;top:auto;left:auto;display:none;float:none;max-width:none;padding:0;margin:0 15px;background-color:transparent;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.nav-collapse .open>.dropdown-menu{display:block}.nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none}.nav-collapse .dropdown-menu .divider{display:none}.nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none}.nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}.navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111;border-bottom-color:#111}.navbar .nav-collapse .nav.pull-right{float:none;margin-left:0}.nav-collapse,.nav-collapse.collapse{height:0;overflow:hidden}.navbar .btn-navbar{display:block}.navbar-static .navbar-inner{padding-right:10px;padding-left:10px}}@media(min-width:980px){.nav-collapse.collapse{height:auto!important;overflow:visible!important}} diff --git a/docs/_static/bootstrap-2.3.2/css/bootstrap.css b/docs/_static/bootstrap-2.3.2/css/bootstrap.css new file mode 100644 index 00000000..b725064a --- /dev/null +++ b/docs/_static/bootstrap-2.3.2/css/bootstrap.css @@ -0,0 +1,6167 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ + +.clearfix { + *zoom: 1; +} + +.clearfix:before, +.clearfix:after { + display: table; + line-height: 0; + content: ""; +} + +.clearfix:after { + clear: both; +} + +.hide-text { + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; +} + +.input-block-level { + display: block; + width: 100%; + min-height: 30px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +nav, +section { + display: block; +} + +audio, +canvas, +video { + display: inline-block; + *display: inline; + *zoom: 1; +} + +audio:not([controls]) { + display: none; +} + +html { + font-size: 100%; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} + +a:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +a:hover, +a:active { + outline: 0; +} + +sub, +sup { + position: relative; + font-size: 75%; + line-height: 0; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + width: auto\9; + height: auto; + max-width: 100%; + vertical-align: middle; + border: 0; + -ms-interpolation-mode: bicubic; +} + +#map_canvas img, +.google-maps img { + max-width: none; +} + +button, +input, +select, +textarea { + margin: 0; + font-size: 100%; + vertical-align: middle; +} + +button, +input { + *overflow: visible; + line-height: normal; +} + +button::-moz-focus-inner, +input::-moz-focus-inner { + padding: 0; + border: 0; +} + +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + cursor: pointer; + -webkit-appearance: button; +} + +label, +select, +button, +input[type="button"], +input[type="reset"], +input[type="submit"], +input[type="radio"], +input[type="checkbox"] { + cursor: pointer; +} + +input[type="search"] { + -webkit-box-sizing: content-box; + -moz-box-sizing: content-box; + box-sizing: content-box; + -webkit-appearance: textfield; +} + +input[type="search"]::-webkit-search-decoration, +input[type="search"]::-webkit-search-cancel-button { + -webkit-appearance: none; +} + +textarea { + overflow: auto; + vertical-align: top; +} + +@media print { + * { + color: #000 !important; + text-shadow: none !important; + background: transparent !important; + box-shadow: none !important; + } + a, + a:visited { + text-decoration: underline; + } + a[href]:after { + content: " (" attr(href) ")"; + } + abbr[title]:after { + content: " (" attr(title) ")"; + } + .ir a:after, + a[href^="javascript:"]:after, + a[href^="#"]:after { + content: ""; + } + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + thead { + display: table-header-group; + } + tr, + img { + page-break-inside: avoid; + } + img { + max-width: 100% !important; + } + @page { + margin: 0.5cm; + } + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + h2, + h3 { + page-break-after: avoid; + } +} + +body { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 20px; + color: #333333; + background-color: #ffffff; +} + +a { + color: #0088cc; + text-decoration: none; +} + +a:hover, +a:focus { + color: #005580; + text-decoration: underline; +} + +.img-rounded { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.img-polaroid { + padding: 4px; + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); +} + +.img-circle { + -webkit-border-radius: 500px; + -moz-border-radius: 500px; + border-radius: 500px; +} + +.row { + margin-left: -20px; + *zoom: 1; +} + +.row:before, +.row:after { + display: table; + line-height: 0; + content: ""; +} + +.row:after { + clear: both; +} + +[class*="span"] { + float: left; + min-height: 1px; + margin-left: 20px; +} + +.container, +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.span12 { + width: 940px; +} + +.span11 { + width: 860px; +} + +.span10 { + width: 780px; +} + +.span9 { + width: 700px; +} + +.span8 { + width: 620px; +} + +.span7 { + width: 540px; +} + +.span6 { + width: 460px; +} + +.span5 { + width: 380px; +} + +.span4 { + width: 300px; +} + +.span3 { + width: 220px; +} + +.span2 { + width: 140px; +} + +.span1 { + width: 60px; +} + +.offset12 { + margin-left: 980px; +} + +.offset11 { + margin-left: 900px; +} + +.offset10 { + margin-left: 820px; +} + +.offset9 { + margin-left: 740px; +} + +.offset8 { + margin-left: 660px; +} + +.offset7 { + margin-left: 580px; +} + +.offset6 { + margin-left: 500px; +} + +.offset5 { + margin-left: 420px; +} + +.offset4 { + margin-left: 340px; +} + +.offset3 { + margin-left: 260px; +} + +.offset2 { + margin-left: 180px; +} + +.offset1 { + margin-left: 100px; +} + +.row-fluid { + width: 100%; + *zoom: 1; +} + +.row-fluid:before, +.row-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.row-fluid:after { + clear: both; +} + +.row-fluid [class*="span"] { + display: block; + float: left; + width: 100%; + min-height: 30px; + margin-left: 2.127659574468085%; + *margin-left: 2.074468085106383%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.row-fluid [class*="span"]:first-child { + margin-left: 0; +} + +.row-fluid .controls-row [class*="span"] + [class*="span"] { + margin-left: 2.127659574468085%; +} + +.row-fluid .span12 { + width: 100%; + *width: 99.94680851063829%; +} + +.row-fluid .span11 { + width: 91.48936170212765%; + *width: 91.43617021276594%; +} + +.row-fluid .span10 { + width: 82.97872340425532%; + *width: 82.92553191489361%; +} + +.row-fluid .span9 { + width: 74.46808510638297%; + *width: 74.41489361702126%; +} + +.row-fluid .span8 { + width: 65.95744680851064%; + *width: 65.90425531914893%; +} + +.row-fluid .span7 { + width: 57.44680851063829%; + *width: 57.39361702127659%; +} + +.row-fluid .span6 { + width: 48.93617021276595%; + *width: 48.88297872340425%; +} + +.row-fluid .span5 { + width: 40.42553191489362%; + *width: 40.37234042553192%; +} + +.row-fluid .span4 { + width: 31.914893617021278%; + *width: 31.861702127659576%; +} + +.row-fluid .span3 { + width: 23.404255319148934%; + *width: 23.351063829787233%; +} + +.row-fluid .span2 { + width: 14.893617021276595%; + *width: 14.840425531914894%; +} + +.row-fluid .span1 { + width: 6.382978723404255%; + *width: 6.329787234042553%; +} + +.row-fluid .offset12 { + margin-left: 104.25531914893617%; + *margin-left: 104.14893617021275%; +} + +.row-fluid .offset12:first-child { + margin-left: 102.12765957446808%; + *margin-left: 102.02127659574467%; +} + +.row-fluid .offset11 { + margin-left: 95.74468085106382%; + *margin-left: 95.6382978723404%; +} + +.row-fluid .offset11:first-child { + margin-left: 93.61702127659574%; + *margin-left: 93.51063829787232%; +} + +.row-fluid .offset10 { + margin-left: 87.23404255319149%; + *margin-left: 87.12765957446807%; +} + +.row-fluid .offset10:first-child { + margin-left: 85.1063829787234%; + *margin-left: 84.99999999999999%; +} + +.row-fluid .offset9 { + margin-left: 78.72340425531914%; + *margin-left: 78.61702127659572%; +} + +.row-fluid .offset9:first-child { + margin-left: 76.59574468085106%; + *margin-left: 76.48936170212764%; +} + +.row-fluid .offset8 { + margin-left: 70.2127659574468%; + *margin-left: 70.10638297872339%; +} + +.row-fluid .offset8:first-child { + margin-left: 68.08510638297872%; + *margin-left: 67.9787234042553%; +} + +.row-fluid .offset7 { + margin-left: 61.70212765957446%; + *margin-left: 61.59574468085106%; +} + +.row-fluid .offset7:first-child { + margin-left: 59.574468085106375%; + *margin-left: 59.46808510638297%; +} + +.row-fluid .offset6 { + margin-left: 53.191489361702125%; + *margin-left: 53.085106382978715%; +} + +.row-fluid .offset6:first-child { + margin-left: 51.063829787234035%; + *margin-left: 50.95744680851063%; +} + +.row-fluid .offset5 { + margin-left: 44.68085106382979%; + *margin-left: 44.57446808510638%; +} + +.row-fluid .offset5:first-child { + margin-left: 42.5531914893617%; + *margin-left: 42.4468085106383%; +} + +.row-fluid .offset4 { + margin-left: 36.170212765957444%; + *margin-left: 36.06382978723405%; +} + +.row-fluid .offset4:first-child { + margin-left: 34.04255319148936%; + *margin-left: 33.93617021276596%; +} + +.row-fluid .offset3 { + margin-left: 27.659574468085104%; + *margin-left: 27.5531914893617%; +} + +.row-fluid .offset3:first-child { + margin-left: 25.53191489361702%; + *margin-left: 25.425531914893618%; +} + +.row-fluid .offset2 { + margin-left: 19.148936170212764%; + *margin-left: 19.04255319148936%; +} + +.row-fluid .offset2:first-child { + margin-left: 17.02127659574468%; + *margin-left: 16.914893617021278%; +} + +.row-fluid .offset1 { + margin-left: 10.638297872340425%; + *margin-left: 10.53191489361702%; +} + +.row-fluid .offset1:first-child { + margin-left: 8.51063829787234%; + *margin-left: 8.404255319148938%; +} + +[class*="span"].hide, +.row-fluid [class*="span"].hide { + display: none; +} + +[class*="span"].pull-right, +.row-fluid [class*="span"].pull-right { + float: right; +} + +.container { + margin-right: auto; + margin-left: auto; + *zoom: 1; +} + +.container:before, +.container:after { + display: table; + line-height: 0; + content: ""; +} + +.container:after { + clear: both; +} + +.container-fluid { + padding-right: 20px; + padding-left: 20px; + *zoom: 1; +} + +.container-fluid:before, +.container-fluid:after { + display: table; + line-height: 0; + content: ""; +} + +.container-fluid:after { + clear: both; +} + +p { + margin: 0 0 10px; +} + +.lead { + margin-bottom: 20px; + font-size: 21px; + font-weight: 200; + line-height: 30px; +} + +small { + font-size: 85%; +} + +strong { + font-weight: bold; +} + +em { + font-style: italic; +} + +cite { + font-style: normal; +} + +.muted { + color: #999999; +} + +a.muted:hover, +a.muted:focus { + color: #808080; +} + +.text-warning { + color: #c09853; +} + +a.text-warning:hover, +a.text-warning:focus { + color: #a47e3c; +} + +.text-error { + color: #b94a48; +} + +a.text-error:hover, +a.text-error:focus { + color: #953b39; +} + +.text-info { + color: #3a87ad; +} + +a.text-info:hover, +a.text-info:focus { + color: #2d6987; +} + +.text-success { + color: #468847; +} + +a.text-success:hover, +a.text-success:focus { + color: #356635; +} + +.text-left { + text-align: left; +} + +.text-right { + text-align: right; +} + +.text-center { + text-align: center; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 10px 0; + font-family: inherit; + font-weight: bold; + line-height: 20px; + color: inherit; + text-rendering: optimizelegibility; +} + +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-weight: normal; + line-height: 1; + color: #999999; +} + +h1, +h2, +h3 { + line-height: 40px; +} + +h1 { + font-size: 38.5px; +} + +h2 { + font-size: 31.5px; +} + +h3 { + font-size: 24.5px; +} + +h4 { + font-size: 17.5px; +} + +h5 { + font-size: 14px; +} + +h6 { + font-size: 11.9px; +} + +h1 small { + font-size: 24.5px; +} + +h2 small { + font-size: 17.5px; +} + +h3 small { + font-size: 14px; +} + +h4 small { + font-size: 14px; +} + +.page-header { + padding-bottom: 9px; + margin: 20px 0 30px; + border-bottom: 1px solid #eeeeee; +} + +ul, +ol { + padding: 0; + margin: 0 0 10px 25px; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-bottom: 0; +} + +li { + line-height: 20px; +} + +ul.unstyled, +ol.unstyled { + margin-left: 0; + list-style: none; +} + +ul.inline, +ol.inline { + margin-left: 0; + list-style: none; +} + +ul.inline > li, +ol.inline > li { + display: inline-block; + *display: inline; + padding-right: 5px; + padding-left: 5px; + *zoom: 1; +} + +dl { + margin-bottom: 20px; +} + +dt, +dd { + line-height: 20px; +} + +dt { + font-weight: bold; +} + +dd { + margin-left: 10px; +} + +.dl-horizontal { + *zoom: 1; +} + +.dl-horizontal:before, +.dl-horizontal:after { + display: table; + line-height: 0; + content: ""; +} + +.dl-horizontal:after { + clear: both; +} + +.dl-horizontal dt { + float: left; + width: 160px; + overflow: hidden; + clear: left; + text-align: right; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dl-horizontal dd { + margin-left: 180px; +} + +hr { + margin: 20px 0; + border: 0; + border-top: 1px solid #eeeeee; + border-bottom: 1px solid #ffffff; +} + +abbr[title], +abbr[data-original-title] { + cursor: help; + border-bottom: 1px dotted #999999; +} + +abbr.initialism { + font-size: 90%; + text-transform: uppercase; +} + +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eeeeee; +} + +blockquote p { + margin-bottom: 0; + font-size: 17.5px; + font-weight: 300; + line-height: 1.25; +} + +blockquote small { + display: block; + line-height: 20px; + color: #999999; +} + +blockquote small:before { + content: '\2014 \00A0'; +} + +blockquote.pull-right { + float: right; + padding-right: 15px; + padding-left: 0; + border-right: 5px solid #eeeeee; + border-left: 0; +} + +blockquote.pull-right p, +blockquote.pull-right small { + text-align: right; +} + +blockquote.pull-right small:before { + content: ''; +} + +blockquote.pull-right small:after { + content: '\00A0 \2014'; +} + +q:before, +q:after, +blockquote:before, +blockquote:after { + content: ""; +} + +address { + display: block; + margin-bottom: 20px; + font-style: normal; + line-height: 20px; +} + +code, +pre { + padding: 0 3px 2px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; + font-size: 12px; + color: #333333; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +code { + padding: 2px 4px; + color: #d14; + white-space: nowrap; + background-color: #f7f7f9; + border: 1px solid #e1e1e8; +} + +pre { + display: block; + padding: 9.5px; + margin: 0 0 10px; + font-size: 13px; + line-height: 20px; + word-break: break-all; + word-wrap: break-word; + white-space: pre; + white-space: pre-wrap; + background-color: #f5f5f5; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +pre.prettyprint { + margin-bottom: 20px; +} + +pre code { + padding: 0; + color: inherit; + white-space: pre; + white-space: pre-wrap; + background-color: transparent; + border: 0; +} + +.pre-scrollable { + max-height: 340px; + overflow-y: scroll; +} + +form { + margin: 0 0 20px; +} + +fieldset { + padding: 0; + margin: 0; + border: 0; +} + +legend { + display: block; + width: 100%; + padding: 0; + margin-bottom: 20px; + font-size: 21px; + line-height: 40px; + color: #333333; + border: 0; + border-bottom: 1px solid #e5e5e5; +} + +legend small { + font-size: 15px; + color: #999999; +} + +label, +input, +button, +select, +textarea { + font-size: 14px; + font-weight: normal; + line-height: 20px; +} + +input, +button, +select, +textarea { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +label { + display: block; + margin-bottom: 5px; +} + +select, +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + display: inline-block; + height: 20px; + padding: 4px 6px; + margin-bottom: 10px; + font-size: 14px; + line-height: 20px; + color: #555555; + vertical-align: middle; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +input, +textarea, +.uneditable-input { + width: 206px; +} + +textarea { + height: auto; +} + +textarea, +input[type="text"], +input[type="password"], +input[type="datetime"], +input[type="datetime-local"], +input[type="date"], +input[type="month"], +input[type="time"], +input[type="week"], +input[type="number"], +input[type="email"], +input[type="url"], +input[type="search"], +input[type="tel"], +input[type="color"], +.uneditable-input { + background-color: #ffffff; + border: 1px solid #cccccc; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -webkit-transition: border linear 0.2s, box-shadow linear 0.2s; + -moz-transition: border linear 0.2s, box-shadow linear 0.2s; + -o-transition: border linear 0.2s, box-shadow linear 0.2s; + transition: border linear 0.2s, box-shadow linear 0.2s; +} + +textarea:focus, +input[type="text"]:focus, +input[type="password"]:focus, +input[type="datetime"]:focus, +input[type="datetime-local"]:focus, +input[type="date"]:focus, +input[type="month"]:focus, +input[type="time"]:focus, +input[type="week"]:focus, +input[type="number"]:focus, +input[type="email"]:focus, +input[type="url"]:focus, +input[type="search"]:focus, +input[type="tel"]:focus, +input[type="color"]:focus, +.uneditable-input:focus { + border-color: rgba(82, 168, 236, 0.8); + outline: 0; + outline: thin dotted \9; + /* IE6-9 */ + + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 8px rgba(82, 168, 236, 0.6); +} + +input[type="radio"], +input[type="checkbox"] { + margin: 4px 0 0; + margin-top: 1px \9; + *margin-top: 0; + line-height: normal; +} + +input[type="file"], +input[type="image"], +input[type="submit"], +input[type="reset"], +input[type="button"], +input[type="radio"], +input[type="checkbox"] { + width: auto; +} + +select, +input[type="file"] { + height: 30px; + /* In IE7, the height of the select element cannot be changed by height, only font-size */ + + *margin-top: 4px; + /* For IE7, add top margin to align select with labels */ + + line-height: 30px; +} + +select { + width: 220px; + background-color: #ffffff; + border: 1px solid #cccccc; +} + +select[multiple], +select[size] { + height: auto; +} + +select:focus, +input[type="file"]:focus, +input[type="radio"]:focus, +input[type="checkbox"]:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.uneditable-input, +.uneditable-textarea { + color: #999999; + cursor: not-allowed; + background-color: #fcfcfc; + border-color: #cccccc; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.025); +} + +.uneditable-input { + overflow: hidden; + white-space: nowrap; +} + +.uneditable-textarea { + width: auto; + height: auto; +} + +input:-moz-placeholder, +textarea:-moz-placeholder { + color: #999999; +} + +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: #999999; +} + +input::-webkit-input-placeholder, +textarea::-webkit-input-placeholder { + color: #999999; +} + +.radio, +.checkbox { + min-height: 20px; + padding-left: 20px; +} + +.radio input[type="radio"], +.checkbox input[type="checkbox"] { + float: left; + margin-left: -20px; +} + +.controls > .radio:first-child, +.controls > .checkbox:first-child { + padding-top: 5px; +} + +.radio.inline, +.checkbox.inline { + display: inline-block; + padding-top: 5px; + margin-bottom: 0; + vertical-align: middle; +} + +.radio.inline + .radio.inline, +.checkbox.inline + .checkbox.inline { + margin-left: 10px; +} + +.input-mini { + width: 60px; +} + +.input-small { + width: 90px; +} + +.input-medium { + width: 150px; +} + +.input-large { + width: 210px; +} + +.input-xlarge { + width: 270px; +} + +.input-xxlarge { + width: 530px; +} + +input[class*="span"], +select[class*="span"], +textarea[class*="span"], +.uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"] { + float: none; + margin-left: 0; +} + +.input-append input[class*="span"], +.input-append .uneditable-input[class*="span"], +.input-prepend input[class*="span"], +.input-prepend .uneditable-input[class*="span"], +.row-fluid input[class*="span"], +.row-fluid select[class*="span"], +.row-fluid textarea[class*="span"], +.row-fluid .uneditable-input[class*="span"], +.row-fluid .input-prepend [class*="span"], +.row-fluid .input-append [class*="span"] { + display: inline-block; +} + +input, +textarea, +.uneditable-input { + margin-left: 0; +} + +.controls-row [class*="span"] + [class*="span"] { + margin-left: 20px; +} + +input.span12, +textarea.span12, +.uneditable-input.span12 { + width: 926px; +} + +input.span11, +textarea.span11, +.uneditable-input.span11 { + width: 846px; +} + +input.span10, +textarea.span10, +.uneditable-input.span10 { + width: 766px; +} + +input.span9, +textarea.span9, +.uneditable-input.span9 { + width: 686px; +} + +input.span8, +textarea.span8, +.uneditable-input.span8 { + width: 606px; +} + +input.span7, +textarea.span7, +.uneditable-input.span7 { + width: 526px; +} + +input.span6, +textarea.span6, +.uneditable-input.span6 { + width: 446px; +} + +input.span5, +textarea.span5, +.uneditable-input.span5 { + width: 366px; +} + +input.span4, +textarea.span4, +.uneditable-input.span4 { + width: 286px; +} + +input.span3, +textarea.span3, +.uneditable-input.span3 { + width: 206px; +} + +input.span2, +textarea.span2, +.uneditable-input.span2 { + width: 126px; +} + +input.span1, +textarea.span1, +.uneditable-input.span1 { + width: 46px; +} + +.controls-row { + *zoom: 1; +} + +.controls-row:before, +.controls-row:after { + display: table; + line-height: 0; + content: ""; +} + +.controls-row:after { + clear: both; +} + +.controls-row [class*="span"], +.row-fluid .controls-row [class*="span"] { + float: left; +} + +.controls-row .checkbox[class*="span"], +.controls-row .radio[class*="span"] { + padding-top: 5px; +} + +input[disabled], +select[disabled], +textarea[disabled], +input[readonly], +select[readonly], +textarea[readonly] { + cursor: not-allowed; + background-color: #eeeeee; +} + +input[type="radio"][disabled], +input[type="checkbox"][disabled], +input[type="radio"][readonly], +input[type="checkbox"][readonly] { + background-color: transparent; +} + +.control-group.warning .control-label, +.control-group.warning .help-block, +.control-group.warning .help-inline { + color: #c09853; +} + +.control-group.warning .checkbox, +.control-group.warning .radio, +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + color: #c09853; +} + +.control-group.warning input, +.control-group.warning select, +.control-group.warning textarea { + border-color: #c09853; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.warning input:focus, +.control-group.warning select:focus, +.control-group.warning textarea:focus { + border-color: #a47e3c; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #dbc59e; +} + +.control-group.warning .input-prepend .add-on, +.control-group.warning .input-append .add-on { + color: #c09853; + background-color: #fcf8e3; + border-color: #c09853; +} + +.control-group.error .control-label, +.control-group.error .help-block, +.control-group.error .help-inline { + color: #b94a48; +} + +.control-group.error .checkbox, +.control-group.error .radio, +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + color: #b94a48; +} + +.control-group.error input, +.control-group.error select, +.control-group.error textarea { + border-color: #b94a48; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.error input:focus, +.control-group.error select:focus, +.control-group.error textarea:focus { + border-color: #953b39; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #d59392; +} + +.control-group.error .input-prepend .add-on, +.control-group.error .input-append .add-on { + color: #b94a48; + background-color: #f2dede; + border-color: #b94a48; +} + +.control-group.success .control-label, +.control-group.success .help-block, +.control-group.success .help-inline { + color: #468847; +} + +.control-group.success .checkbox, +.control-group.success .radio, +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + color: #468847; +} + +.control-group.success input, +.control-group.success select, +.control-group.success textarea { + border-color: #468847; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.success input:focus, +.control-group.success select:focus, +.control-group.success textarea:focus { + border-color: #356635; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7aba7b; +} + +.control-group.success .input-prepend .add-on, +.control-group.success .input-append .add-on { + color: #468847; + background-color: #dff0d8; + border-color: #468847; +} + +.control-group.info .control-label, +.control-group.info .help-block, +.control-group.info .help-inline { + color: #3a87ad; +} + +.control-group.info .checkbox, +.control-group.info .radio, +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + color: #3a87ad; +} + +.control-group.info input, +.control-group.info select, +.control-group.info textarea { + border-color: #3a87ad; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.control-group.info input:focus, +.control-group.info select:focus, +.control-group.info textarea:focus { + border-color: #2d6987; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #7ab5d3; +} + +.control-group.info .input-prepend .add-on, +.control-group.info .input-append .add-on { + color: #3a87ad; + background-color: #d9edf7; + border-color: #3a87ad; +} + +input:focus:invalid, +textarea:focus:invalid, +select:focus:invalid { + color: #b94a48; + border-color: #ee5f5b; +} + +input:focus:invalid:focus, +textarea:focus:invalid:focus, +select:focus:invalid:focus { + border-color: #e9322d; + -webkit-box-shadow: 0 0 6px #f8b9b7; + -moz-box-shadow: 0 0 6px #f8b9b7; + box-shadow: 0 0 6px #f8b9b7; +} + +.form-actions { + padding: 19px 20px 20px; + margin-top: 20px; + margin-bottom: 20px; + background-color: #f5f5f5; + border-top: 1px solid #e5e5e5; + *zoom: 1; +} + +.form-actions:before, +.form-actions:after { + display: table; + line-height: 0; + content: ""; +} + +.form-actions:after { + clear: both; +} + +.help-block, +.help-inline { + color: #595959; +} + +.help-block { + display: block; + margin-bottom: 10px; +} + +.help-inline { + display: inline-block; + *display: inline; + padding-left: 5px; + vertical-align: middle; + *zoom: 1; +} + +.input-append, +.input-prepend { + display: inline-block; + margin-bottom: 10px; + font-size: 0; + white-space: nowrap; + vertical-align: middle; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input, +.input-append .dropdown-menu, +.input-prepend .dropdown-menu, +.input-append .popover, +.input-prepend .popover { + font-size: 14px; +} + +.input-append input, +.input-prepend input, +.input-append select, +.input-prepend select, +.input-append .uneditable-input, +.input-prepend .uneditable-input { + position: relative; + margin-bottom: 0; + *margin-left: 0; + vertical-align: top; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append input:focus, +.input-prepend input:focus, +.input-append select:focus, +.input-prepend select:focus, +.input-append .uneditable-input:focus, +.input-prepend .uneditable-input:focus { + z-index: 2; +} + +.input-append .add-on, +.input-prepend .add-on { + display: inline-block; + width: auto; + height: 20px; + min-width: 16px; + padding: 4px 5px; + font-size: 14px; + font-weight: normal; + line-height: 20px; + text-align: center; + text-shadow: 0 1px 0 #ffffff; + background-color: #eeeeee; + border: 1px solid #ccc; +} + +.input-append .add-on, +.input-prepend .add-on, +.input-append .btn, +.input-prepend .btn, +.input-append .btn-group > .dropdown-toggle, +.input-prepend .btn-group > .dropdown-toggle { + vertical-align: top; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-append .active, +.input-prepend .active { + background-color: #a9dba9; + border-color: #46a546; +} + +.input-prepend .add-on, +.input-prepend .btn { + margin-right: -1px; +} + +.input-prepend .add-on:first-child, +.input-prepend .btn:first-child { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input, +.input-append select, +.input-append .uneditable-input { + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-append input + .btn-group .btn:last-child, +.input-append select + .btn-group .btn:last-child, +.input-append .uneditable-input + .btn-group .btn:last-child { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-append .add-on, +.input-append .btn, +.input-append .btn-group { + margin-left: -1px; +} + +.input-append .add-on:last-child, +.input-append .btn:last-child, +.input-append .btn-group:last-child > .dropdown-toggle { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append input, +.input-prepend.input-append select, +.input-prepend.input-append .uneditable-input { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.input-prepend.input-append input + .btn-group .btn, +.input-prepend.input-append select + .btn-group .btn, +.input-prepend.input-append .uneditable-input + .btn-group .btn { + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .add-on:first-child, +.input-prepend.input-append .btn:first-child { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.input-prepend.input-append .add-on:last-child, +.input-prepend.input-append .btn:last-child { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.input-prepend.input-append .btn-group:first-child { + margin-left: 0; +} + +input.search-query { + padding-right: 14px; + padding-right: 4px \9; + padding-left: 14px; + padding-left: 4px \9; + /* IE7-8 doesn't have border-radius, so don't indent the padding */ + + margin-bottom: 0; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +/* Allow for input prepend/append in search forms */ + +.form-search .input-append .search-query, +.form-search .input-prepend .search-query { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.form-search .input-append .search-query { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search .input-append .btn { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .search-query { + -webkit-border-radius: 0 14px 14px 0; + -moz-border-radius: 0 14px 14px 0; + border-radius: 0 14px 14px 0; +} + +.form-search .input-prepend .btn { + -webkit-border-radius: 14px 0 0 14px; + -moz-border-radius: 14px 0 0 14px; + border-radius: 14px 0 0 14px; +} + +.form-search input, +.form-inline input, +.form-horizontal input, +.form-search textarea, +.form-inline textarea, +.form-horizontal textarea, +.form-search select, +.form-inline select, +.form-horizontal select, +.form-search .help-inline, +.form-inline .help-inline, +.form-horizontal .help-inline, +.form-search .uneditable-input, +.form-inline .uneditable-input, +.form-horizontal .uneditable-input, +.form-search .input-prepend, +.form-inline .input-prepend, +.form-horizontal .input-prepend, +.form-search .input-append, +.form-inline .input-append, +.form-horizontal .input-append { + display: inline-block; + *display: inline; + margin-bottom: 0; + vertical-align: middle; + *zoom: 1; +} + +.form-search .hide, +.form-inline .hide, +.form-horizontal .hide { + display: none; +} + +.form-search label, +.form-inline label, +.form-search .btn-group, +.form-inline .btn-group { + display: inline-block; +} + +.form-search .input-append, +.form-inline .input-append, +.form-search .input-prepend, +.form-inline .input-prepend { + margin-bottom: 0; +} + +.form-search .radio, +.form-search .checkbox, +.form-inline .radio, +.form-inline .checkbox { + padding-left: 0; + margin-bottom: 0; + vertical-align: middle; +} + +.form-search .radio input[type="radio"], +.form-search .checkbox input[type="checkbox"], +.form-inline .radio input[type="radio"], +.form-inline .checkbox input[type="checkbox"] { + float: left; + margin-right: 3px; + margin-left: 0; +} + +.control-group { + margin-bottom: 10px; +} + +legend + .control-group { + margin-top: 20px; + -webkit-margin-top-collapse: separate; +} + +.form-horizontal .control-group { + margin-bottom: 20px; + *zoom: 1; +} + +.form-horizontal .control-group:before, +.form-horizontal .control-group:after { + display: table; + line-height: 0; + content: ""; +} + +.form-horizontal .control-group:after { + clear: both; +} + +.form-horizontal .control-label { + float: left; + width: 160px; + padding-top: 5px; + text-align: right; +} + +.form-horizontal .controls { + *display: inline-block; + *padding-left: 20px; + margin-left: 180px; + *margin-left: 0; +} + +.form-horizontal .controls:first-child { + *padding-left: 180px; +} + +.form-horizontal .help-block { + margin-bottom: 0; +} + +.form-horizontal input + .help-block, +.form-horizontal select + .help-block, +.form-horizontal textarea + .help-block, +.form-horizontal .uneditable-input + .help-block, +.form-horizontal .input-prepend + .help-block, +.form-horizontal .input-append + .help-block { + margin-top: 10px; +} + +.form-horizontal .form-actions { + padding-left: 180px; +} + +table { + max-width: 100%; + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +.table { + width: 100%; + margin-bottom: 20px; +} + +.table th, +.table td { + padding: 8px; + line-height: 20px; + text-align: left; + vertical-align: top; + border-top: 1px solid #dddddd; +} + +.table th { + font-weight: bold; +} + +.table thead th { + vertical-align: bottom; +} + +.table caption + thead tr:first-child th, +.table caption + thead tr:first-child td, +.table colgroup + thead tr:first-child th, +.table colgroup + thead tr:first-child td, +.table thead:first-child tr:first-child th, +.table thead:first-child tr:first-child td { + border-top: 0; +} + +.table tbody + tbody { + border-top: 2px solid #dddddd; +} + +.table .table { + background-color: #ffffff; +} + +.table-condensed th, +.table-condensed td { + padding: 4px 5px; +} + +.table-bordered { + border: 1px solid #dddddd; + border-collapse: separate; + *border-collapse: collapse; + border-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.table-bordered th, +.table-bordered td { + border-left: 1px solid #dddddd; +} + +.table-bordered caption + thead tr:first-child th, +.table-bordered caption + tbody tr:first-child th, +.table-bordered caption + tbody tr:first-child td, +.table-bordered colgroup + thead tr:first-child th, +.table-bordered colgroup + tbody tr:first-child th, +.table-bordered colgroup + tbody tr:first-child td, +.table-bordered thead:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child th, +.table-bordered tbody:first-child tr:first-child td { + border-top: 0; +} + +.table-bordered thead:first-child tr:first-child > th:first-child, +.table-bordered tbody:first-child tr:first-child > td:first-child, +.table-bordered tbody:first-child tr:first-child > th:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered thead:first-child tr:first-child > th:last-child, +.table-bordered tbody:first-child tr:first-child > td:last-child, +.table-bordered tbody:first-child tr:first-child > th:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:first-child, +.table-bordered tbody:last-child tr:last-child > td:first-child, +.table-bordered tbody:last-child tr:last-child > th:first-child, +.table-bordered tfoot:last-child tr:last-child > td:first-child, +.table-bordered tfoot:last-child tr:last-child > th:first-child { + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.table-bordered thead:last-child tr:last-child > th:last-child, +.table-bordered tbody:last-child tr:last-child > td:last-child, +.table-bordered tbody:last-child tr:last-child > th:last-child, +.table-bordered tfoot:last-child tr:last-child > td:last-child, +.table-bordered tfoot:last-child tr:last-child > th:last-child { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomright: 4px; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:first-child { + -webkit-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomleft: 0; +} + +.table-bordered tfoot + tbody:last-child tr:last-child td:last-child { + -webkit-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-bottomright: 0; +} + +.table-bordered caption + thead tr:first-child th:first-child, +.table-bordered caption + tbody tr:first-child td:first-child, +.table-bordered colgroup + thead tr:first-child th:first-child, +.table-bordered colgroup + tbody tr:first-child td:first-child { + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topleft: 4px; +} + +.table-bordered caption + thead tr:first-child th:last-child, +.table-bordered caption + tbody tr:first-child td:last-child, +.table-bordered colgroup + thead tr:first-child th:last-child, +.table-bordered colgroup + tbody tr:first-child td:last-child { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -moz-border-radius-topright: 4px; +} + +.table-striped tbody > tr:nth-child(odd) > td, +.table-striped tbody > tr:nth-child(odd) > th { + background-color: #f9f9f9; +} + +.table-hover tbody tr:hover > td, +.table-hover tbody tr:hover > th { + background-color: #f5f5f5; +} + +table td[class*="span"], +table th[class*="span"], +.row-fluid table td[class*="span"], +.row-fluid table th[class*="span"] { + display: table-cell; + float: none; + margin-left: 0; +} + +.table td.span1, +.table th.span1 { + float: none; + width: 44px; + margin-left: 0; +} + +.table td.span2, +.table th.span2 { + float: none; + width: 124px; + margin-left: 0; +} + +.table td.span3, +.table th.span3 { + float: none; + width: 204px; + margin-left: 0; +} + +.table td.span4, +.table th.span4 { + float: none; + width: 284px; + margin-left: 0; +} + +.table td.span5, +.table th.span5 { + float: none; + width: 364px; + margin-left: 0; +} + +.table td.span6, +.table th.span6 { + float: none; + width: 444px; + margin-left: 0; +} + +.table td.span7, +.table th.span7 { + float: none; + width: 524px; + margin-left: 0; +} + +.table td.span8, +.table th.span8 { + float: none; + width: 604px; + margin-left: 0; +} + +.table td.span9, +.table th.span9 { + float: none; + width: 684px; + margin-left: 0; +} + +.table td.span10, +.table th.span10 { + float: none; + width: 764px; + margin-left: 0; +} + +.table td.span11, +.table th.span11 { + float: none; + width: 844px; + margin-left: 0; +} + +.table td.span12, +.table th.span12 { + float: none; + width: 924px; + margin-left: 0; +} + +.table tbody tr.success > td { + background-color: #dff0d8; +} + +.table tbody tr.error > td { + background-color: #f2dede; +} + +.table tbody tr.warning > td { + background-color: #fcf8e3; +} + +.table tbody tr.info > td { + background-color: #d9edf7; +} + +.table-hover tbody tr.success:hover > td { + background-color: #d0e9c6; +} + +.table-hover tbody tr.error:hover > td { + background-color: #ebcccc; +} + +.table-hover tbody tr.warning:hover > td { + background-color: #faf2cc; +} + +.table-hover tbody tr.info:hover > td { + background-color: #c4e3f3; +} + +[class^="icon-"], +[class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + *margin-right: .3em; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} + +/* White icons with optional class, or on hover/focus/active states of certain elements */ + +.icon-white, +.nav-pills > .active > a > [class^="icon-"], +.nav-pills > .active > a > [class*=" icon-"], +.nav-list > .active > a > [class^="icon-"], +.nav-list > .active > a > [class*=" icon-"], +.navbar-inverse .nav > .active > a > [class^="icon-"], +.navbar-inverse .nav > .active > a > [class*=" icon-"], +.dropdown-menu > li > a:hover > [class^="icon-"], +.dropdown-menu > li > a:focus > [class^="icon-"], +.dropdown-menu > li > a:hover > [class*=" icon-"], +.dropdown-menu > li > a:focus > [class*=" icon-"], +.dropdown-menu > .active > a > [class^="icon-"], +.dropdown-menu > .active > a > [class*=" icon-"], +.dropdown-submenu:hover > a > [class^="icon-"], +.dropdown-submenu:focus > a > [class^="icon-"], +.dropdown-submenu:hover > a > [class*=" icon-"], +.dropdown-submenu:focus > a > [class*=" icon-"] { + background-image: url("../img/glyphicons-halflings-white.png"); +} + +.icon-glass { + background-position: 0 0; +} + +.icon-music { + background-position: -24px 0; +} + +.icon-search { + background-position: -48px 0; +} + +.icon-envelope { + background-position: -72px 0; +} + +.icon-heart { + background-position: -96px 0; +} + +.icon-star { + background-position: -120px 0; +} + +.icon-star-empty { + background-position: -144px 0; +} + +.icon-user { + background-position: -168px 0; +} + +.icon-film { + background-position: -192px 0; +} + +.icon-th-large { + background-position: -216px 0; +} + +.icon-th { + background-position: -240px 0; +} + +.icon-th-list { + background-position: -264px 0; +} + +.icon-ok { + background-position: -288px 0; +} + +.icon-remove { + background-position: -312px 0; +} + +.icon-zoom-in { + background-position: -336px 0; +} + +.icon-zoom-out { + background-position: -360px 0; +} + +.icon-off { + background-position: -384px 0; +} + +.icon-signal { + background-position: -408px 0; +} + +.icon-cog { + background-position: -432px 0; +} + +.icon-trash { + background-position: -456px 0; +} + +.icon-home { + background-position: 0 -24px; +} + +.icon-file { + background-position: -24px -24px; +} + +.icon-time { + background-position: -48px -24px; +} + +.icon-road { + background-position: -72px -24px; +} + +.icon-download-alt { + background-position: -96px -24px; +} + +.icon-download { + background-position: -120px -24px; +} + +.icon-upload { + background-position: -144px -24px; +} + +.icon-inbox { + background-position: -168px -24px; +} + +.icon-play-circle { + background-position: -192px -24px; +} + +.icon-repeat { + background-position: -216px -24px; +} + +.icon-refresh { + background-position: -240px -24px; +} + +.icon-list-alt { + background-position: -264px -24px; +} + +.icon-lock { + background-position: -287px -24px; +} + +.icon-flag { + background-position: -312px -24px; +} + +.icon-headphones { + background-position: -336px -24px; +} + +.icon-volume-off { + background-position: -360px -24px; +} + +.icon-volume-down { + background-position: -384px -24px; +} + +.icon-volume-up { + background-position: -408px -24px; +} + +.icon-qrcode { + background-position: -432px -24px; +} + +.icon-barcode { + background-position: -456px -24px; +} + +.icon-tag { + background-position: 0 -48px; +} + +.icon-tags { + background-position: -25px -48px; +} + +.icon-book { + background-position: -48px -48px; +} + +.icon-bookmark { + background-position: -72px -48px; +} + +.icon-print { + background-position: -96px -48px; +} + +.icon-camera { + background-position: -120px -48px; +} + +.icon-font { + background-position: -144px -48px; +} + +.icon-bold { + background-position: -167px -48px; +} + +.icon-italic { + background-position: -192px -48px; +} + +.icon-text-height { + background-position: -216px -48px; +} + +.icon-text-width { + background-position: -240px -48px; +} + +.icon-align-left { + background-position: -264px -48px; +} + +.icon-align-center { + background-position: -288px -48px; +} + +.icon-align-right { + background-position: -312px -48px; +} + +.icon-align-justify { + background-position: -336px -48px; +} + +.icon-list { + background-position: -360px -48px; +} + +.icon-indent-left { + background-position: -384px -48px; +} + +.icon-indent-right { + background-position: -408px -48px; +} + +.icon-facetime-video { + background-position: -432px -48px; +} + +.icon-picture { + background-position: -456px -48px; +} + +.icon-pencil { + background-position: 0 -72px; +} + +.icon-map-marker { + background-position: -24px -72px; +} + +.icon-adjust { + background-position: -48px -72px; +} + +.icon-tint { + background-position: -72px -72px; +} + +.icon-edit { + background-position: -96px -72px; +} + +.icon-share { + background-position: -120px -72px; +} + +.icon-check { + background-position: -144px -72px; +} + +.icon-move { + background-position: -168px -72px; +} + +.icon-step-backward { + background-position: -192px -72px; +} + +.icon-fast-backward { + background-position: -216px -72px; +} + +.icon-backward { + background-position: -240px -72px; +} + +.icon-play { + background-position: -264px -72px; +} + +.icon-pause { + background-position: -288px -72px; +} + +.icon-stop { + background-position: -312px -72px; +} + +.icon-forward { + background-position: -336px -72px; +} + +.icon-fast-forward { + background-position: -360px -72px; +} + +.icon-step-forward { + background-position: -384px -72px; +} + +.icon-eject { + background-position: -408px -72px; +} + +.icon-chevron-left { + background-position: -432px -72px; +} + +.icon-chevron-right { + background-position: -456px -72px; +} + +.icon-plus-sign { + background-position: 0 -96px; +} + +.icon-minus-sign { + background-position: -24px -96px; +} + +.icon-remove-sign { + background-position: -48px -96px; +} + +.icon-ok-sign { + background-position: -72px -96px; +} + +.icon-question-sign { + background-position: -96px -96px; +} + +.icon-info-sign { + background-position: -120px -96px; +} + +.icon-screenshot { + background-position: -144px -96px; +} + +.icon-remove-circle { + background-position: -168px -96px; +} + +.icon-ok-circle { + background-position: -192px -96px; +} + +.icon-ban-circle { + background-position: -216px -96px; +} + +.icon-arrow-left { + background-position: -240px -96px; +} + +.icon-arrow-right { + background-position: -264px -96px; +} + +.icon-arrow-up { + background-position: -289px -96px; +} + +.icon-arrow-down { + background-position: -312px -96px; +} + +.icon-share-alt { + background-position: -336px -96px; +} + +.icon-resize-full { + background-position: -360px -96px; +} + +.icon-resize-small { + background-position: -384px -96px; +} + +.icon-plus { + background-position: -408px -96px; +} + +.icon-minus { + background-position: -433px -96px; +} + +.icon-asterisk { + background-position: -456px -96px; +} + +.icon-exclamation-sign { + background-position: 0 -120px; +} + +.icon-gift { + background-position: -24px -120px; +} + +.icon-leaf { + background-position: -48px -120px; +} + +.icon-fire { + background-position: -72px -120px; +} + +.icon-eye-open { + background-position: -96px -120px; +} + +.icon-eye-close { + background-position: -120px -120px; +} + +.icon-warning-sign { + background-position: -144px -120px; +} + +.icon-plane { + background-position: -168px -120px; +} + +.icon-calendar { + background-position: -192px -120px; +} + +.icon-random { + width: 16px; + background-position: -216px -120px; +} + +.icon-comment { + background-position: -240px -120px; +} + +.icon-magnet { + background-position: -264px -120px; +} + +.icon-chevron-up { + background-position: -288px -120px; +} + +.icon-chevron-down { + background-position: -313px -119px; +} + +.icon-retweet { + background-position: -336px -120px; +} + +.icon-shopping-cart { + background-position: -360px -120px; +} + +.icon-folder-close { + width: 16px; + background-position: -384px -120px; +} + +.icon-folder-open { + width: 16px; + background-position: -408px -120px; +} + +.icon-resize-vertical { + background-position: -432px -119px; +} + +.icon-resize-horizontal { + background-position: -456px -118px; +} + +.icon-hdd { + background-position: 0 -144px; +} + +.icon-bullhorn { + background-position: -24px -144px; +} + +.icon-bell { + background-position: -48px -144px; +} + +.icon-certificate { + background-position: -72px -144px; +} + +.icon-thumbs-up { + background-position: -96px -144px; +} + +.icon-thumbs-down { + background-position: -120px -144px; +} + +.icon-hand-right { + background-position: -144px -144px; +} + +.icon-hand-left { + background-position: -168px -144px; +} + +.icon-hand-up { + background-position: -192px -144px; +} + +.icon-hand-down { + background-position: -216px -144px; +} + +.icon-circle-arrow-right { + background-position: -240px -144px; +} + +.icon-circle-arrow-left { + background-position: -264px -144px; +} + +.icon-circle-arrow-up { + background-position: -288px -144px; +} + +.icon-circle-arrow-down { + background-position: -312px -144px; +} + +.icon-globe { + background-position: -336px -144px; +} + +.icon-wrench { + background-position: -360px -144px; +} + +.icon-tasks { + background-position: -384px -144px; +} + +.icon-filter { + background-position: -408px -144px; +} + +.icon-briefcase { + background-position: -432px -144px; +} + +.icon-fullscreen { + background-position: -456px -144px; +} + +.dropup, +.dropdown { + position: relative; +} + +.dropdown-toggle { + *margin-bottom: -3px; +} + +.dropdown-toggle:active, +.open .dropdown-toggle { + outline: 0; +} + +.caret { + display: inline-block; + width: 0; + height: 0; + vertical-align: top; + border-top: 4px solid #000000; + border-right: 4px solid transparent; + border-left: 4px solid transparent; + content: ""; +} + +.dropdown .caret { + margin-top: 8px; + margin-left: 2px; +} + +.dropdown-menu { + position: absolute; + top: 100%; + left: 0; + z-index: 1000; + display: none; + float: left; + min-width: 160px; + padding: 5px 0; + margin: 2px 0 0; + list-style: none; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + *border-right-width: 2px; + *border-bottom-width: 2px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.dropdown-menu .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.dropdown-menu > li > a { + display: block; + padding: 3px 20px; + clear: both; + font-weight: normal; + line-height: 20px; + color: #333333; + white-space: nowrap; +} + +.dropdown-menu > li > a:hover, +.dropdown-menu > li > a:focus, +.dropdown-submenu:hover > a, +.dropdown-submenu:focus > a { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + color: #ffffff; + text-decoration: none; + background-color: #0081c2; + background-image: -moz-linear-gradient(top, #0088cc, #0077b3); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3)); + background-image: -webkit-linear-gradient(top, #0088cc, #0077b3); + background-image: -o-linear-gradient(top, #0088cc, #0077b3); + background-image: linear-gradient(to bottom, #0088cc, #0077b3); + background-repeat: repeat-x; + outline: 0; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0); +} + +.dropdown-menu > .disabled > a, +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + color: #999999; +} + +.dropdown-menu > .disabled > a:hover, +.dropdown-menu > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.open { + *z-index: 1000; +} + +.open > .dropdown-menu { + display: block; +} + +.dropdown-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 990; +} + +.pull-right > .dropdown-menu { + right: 0; + left: auto; +} + +.dropup .caret, +.navbar-fixed-bottom .dropdown .caret { + border-top: 0; + border-bottom: 4px solid #000000; + content: ""; +} + +.dropup .dropdown-menu, +.navbar-fixed-bottom .dropdown .dropdown-menu { + top: auto; + bottom: 100%; + margin-bottom: 1px; +} + +.dropdown-submenu { + position: relative; +} + +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} + +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} + +.dropup .dropdown-submenu > .dropdown-menu { + top: auto; + bottom: 0; + margin-top: 0; + margin-bottom: -2px; + -webkit-border-radius: 5px 5px 5px 0; + -moz-border-radius: 5px 5px 5px 0; + border-radius: 5px 5px 5px 0; +} + +.dropdown-submenu > a:after { + display: block; + float: right; + width: 0; + height: 0; + margin-top: 5px; + margin-right: -10px; + border-color: transparent; + border-left-color: #cccccc; + border-style: solid; + border-width: 5px 0 5px 5px; + content: " "; +} + +.dropdown-submenu:hover > a:after { + border-left-color: #ffffff; +} + +.dropdown-submenu.pull-left { + float: none; +} + +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.dropdown .dropdown-menu .nav-header { + padding-right: 20px; + padding-left: 20px; +} + +.typeahead { + z-index: 1051; + margin-top: 2px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.well { + min-height: 20px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.well blockquote { + border-color: #ddd; + border-color: rgba(0, 0, 0, 0.15); +} + +.well-large { + padding: 24px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.well-small { + padding: 9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.fade { + opacity: 0; + -webkit-transition: opacity 0.15s linear; + -moz-transition: opacity 0.15s linear; + -o-transition: opacity 0.15s linear; + transition: opacity 0.15s linear; +} + +.fade.in { + opacity: 1; +} + +.collapse { + position: relative; + height: 0; + overflow: hidden; + -webkit-transition: height 0.35s ease; + -moz-transition: height 0.35s ease; + -o-transition: height 0.35s ease; + transition: height 0.35s ease; +} + +.collapse.in { + height: auto; +} + +.close { + float: right; + font-size: 20px; + font-weight: bold; + line-height: 20px; + color: #000000; + text-shadow: 0 1px 0 #ffffff; + opacity: 0.2; + filter: alpha(opacity=20); +} + +.close:hover, +.close:focus { + color: #000000; + text-decoration: none; + cursor: pointer; + opacity: 0.4; + filter: alpha(opacity=40); +} + +button.close { + padding: 0; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; +} + +.btn { + display: inline-block; + *display: inline; + padding: 4px 12px; + margin-bottom: 0; + *margin-left: .3em; + font-size: 14px; + line-height: 20px; + color: #333333; + text-align: center; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + vertical-align: middle; + cursor: pointer; + background-color: #f5f5f5; + *background-color: #e6e6e6; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + border: 1px solid #cccccc; + *border: 0; + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + border-bottom-color: #b3b3b3; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn:hover, +.btn:focus, +.btn:active, +.btn.active, +.btn.disabled, +.btn[disabled] { + color: #333333; + background-color: #e6e6e6; + *background-color: #d9d9d9; +} + +.btn:active, +.btn.active { + background-color: #cccccc \9; +} + +.btn:first-child { + *margin-left: 0; +} + +.btn:hover, +.btn:focus { + color: #333333; + text-decoration: none; + background-position: 0 -15px; + -webkit-transition: background-position 0.1s linear; + -moz-transition: background-position 0.1s linear; + -o-transition: background-position 0.1s linear; + transition: background-position 0.1s linear; +} + +.btn:focus { + outline: thin dotted #333; + outline: 5px auto -webkit-focus-ring-color; + outline-offset: -2px; +} + +.btn.active, +.btn:active { + background-image: none; + outline: 0; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn.disabled, +.btn[disabled] { + cursor: default; + background-image: none; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-large { + padding: 11px 19px; + font-size: 17.5px; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.btn-large [class^="icon-"], +.btn-large [class*=" icon-"] { + margin-top: 4px; +} + +.btn-small { + padding: 2px 10px; + font-size: 11.9px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-small [class^="icon-"], +.btn-small [class*=" icon-"] { + margin-top: 0; +} + +.btn-mini [class^="icon-"], +.btn-mini [class*=" icon-"] { + margin-top: -1px; +} + +.btn-mini { + padding: 0 6px; + font-size: 10.5px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.btn-block { + display: block; + width: 100%; + padding-right: 0; + padding-left: 0; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.btn-block + .btn-block { + margin-top: 5px; +} + +input[type="submit"].btn-block, +input[type="reset"].btn-block, +input[type="button"].btn-block { + width: 100%; +} + +.btn-primary.active, +.btn-warning.active, +.btn-danger.active, +.btn-success.active, +.btn-info.active, +.btn-inverse.active { + color: rgba(255, 255, 255, 0.75); +} + +.btn-primary { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #006dcc; + *background-color: #0044cc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(to bottom, #0088cc, #0044cc); + background-repeat: repeat-x; + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.btn-primary.disabled, +.btn-primary[disabled] { + color: #ffffff; + background-color: #0044cc; + *background-color: #003bb3; +} + +.btn-primary:active, +.btn-primary.active { + background-color: #003399 \9; +} + +.btn-warning { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #faa732; + *background-color: #f89406; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + border-color: #f89406 #f89406 #ad6704; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.btn-warning.disabled, +.btn-warning[disabled] { + color: #ffffff; + background-color: #f89406; + *background-color: #df8505; +} + +.btn-warning:active, +.btn-warning.active { + background-color: #c67605 \9; +} + +.btn-danger { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #da4f49; + *background-color: #bd362f; + background-image: -moz-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #bd362f); + background-image: -o-linear-gradient(top, #ee5f5b, #bd362f); + background-image: linear-gradient(to bottom, #ee5f5b, #bd362f); + background-repeat: repeat-x; + border-color: #bd362f #bd362f #802420; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.btn-danger.disabled, +.btn-danger[disabled] { + color: #ffffff; + background-color: #bd362f; + *background-color: #a9302a; +} + +.btn-danger:active, +.btn-danger.active { + background-color: #942a25 \9; +} + +.btn-success { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #5bb75b; + *background-color: #51a351; + background-image: -moz-linear-gradient(top, #62c462, #51a351); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351)); + background-image: -webkit-linear-gradient(top, #62c462, #51a351); + background-image: -o-linear-gradient(top, #62c462, #51a351); + background-image: linear-gradient(to bottom, #62c462, #51a351); + background-repeat: repeat-x; + border-color: #51a351 #51a351 #387038; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.btn-success.disabled, +.btn-success[disabled] { + color: #ffffff; + background-color: #51a351; + *background-color: #499249; +} + +.btn-success:active, +.btn-success.active { + background-color: #408140 \9; +} + +.btn-info { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #49afcd; + *background-color: #2f96b4; + background-image: -moz-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4)); + background-image: -webkit-linear-gradient(top, #5bc0de, #2f96b4); + background-image: -o-linear-gradient(top, #5bc0de, #2f96b4); + background-image: linear-gradient(to bottom, #5bc0de, #2f96b4); + background-repeat: repeat-x; + border-color: #2f96b4 #2f96b4 #1f6377; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.btn-info.disabled, +.btn-info[disabled] { + color: #ffffff; + background-color: #2f96b4; + *background-color: #2a85a0; +} + +.btn-info:active, +.btn-info.active { + background-color: #24748c \9; +} + +.btn-inverse { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #363636; + *background-color: #222222; + background-image: -moz-linear-gradient(top, #444444, #222222); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222)); + background-image: -webkit-linear-gradient(top, #444444, #222222); + background-image: -o-linear-gradient(top, #444444, #222222); + background-image: linear-gradient(to bottom, #444444, #222222); + background-repeat: repeat-x; + border-color: #222222 #222222 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.btn-inverse:hover, +.btn-inverse:focus, +.btn-inverse:active, +.btn-inverse.active, +.btn-inverse.disabled, +.btn-inverse[disabled] { + color: #ffffff; + background-color: #222222; + *background-color: #151515; +} + +.btn-inverse:active, +.btn-inverse.active { + background-color: #080808 \9; +} + +button.btn, +input[type="submit"].btn { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn::-moz-focus-inner, +input[type="submit"].btn::-moz-focus-inner { + padding: 0; + border: 0; +} + +button.btn.btn-large, +input[type="submit"].btn.btn-large { + *padding-top: 7px; + *padding-bottom: 7px; +} + +button.btn.btn-small, +input[type="submit"].btn.btn-small { + *padding-top: 3px; + *padding-bottom: 3px; +} + +button.btn.btn-mini, +input[type="submit"].btn.btn-mini { + *padding-top: 1px; + *padding-bottom: 1px; +} + +.btn-link, +.btn-link:active, +.btn-link[disabled] { + background-color: transparent; + background-image: none; + -webkit-box-shadow: none; + -moz-box-shadow: none; + box-shadow: none; +} + +.btn-link { + color: #0088cc; + cursor: pointer; + border-color: transparent; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-link:hover, +.btn-link:focus { + color: #005580; + text-decoration: underline; + background-color: transparent; +} + +.btn-link[disabled]:hover, +.btn-link[disabled]:focus { + color: #333333; + text-decoration: none; +} + +.btn-group { + position: relative; + display: inline-block; + *display: inline; + *margin-left: .3em; + font-size: 0; + white-space: nowrap; + vertical-align: middle; + *zoom: 1; +} + +.btn-group:first-child { + *margin-left: 0; +} + +.btn-group + .btn-group { + margin-left: 5px; +} + +.btn-toolbar { + margin-top: 10px; + margin-bottom: 10px; + font-size: 0; +} + +.btn-toolbar > .btn + .btn, +.btn-toolbar > .btn-group + .btn, +.btn-toolbar > .btn + .btn-group { + margin-left: 5px; +} + +.btn-group > .btn { + position: relative; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group > .btn + .btn { + margin-left: -1px; +} + +.btn-group > .btn, +.btn-group > .dropdown-menu, +.btn-group > .popover { + font-size: 14px; +} + +.btn-group > .btn-mini { + font-size: 10.5px; +} + +.btn-group > .btn-small { + font-size: 11.9px; +} + +.btn-group > .btn-large { + font-size: 17.5px; +} + +.btn-group > .btn:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.btn-group > .btn:last-child, +.btn-group > .dropdown-toggle { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.btn-group > .btn.large:first-child { + margin-left: 0; + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.btn-group > .btn.large:last-child, +.btn-group > .large.dropdown-toggle { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active { + z-index: 2; +} + +.btn-group .dropdown-toggle:active, +.btn-group.open .dropdown-toggle { + outline: 0; +} + +.btn-group > .btn + .dropdown-toggle { + *padding-top: 5px; + padding-right: 8px; + *padding-bottom: 5px; + padding-left: 8px; + -webkit-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 1px 0 0 rgba(255, 255, 255, 0.125), inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group > .btn-mini + .dropdown-toggle { + *padding-top: 2px; + padding-right: 5px; + *padding-bottom: 2px; + padding-left: 5px; +} + +.btn-group > .btn-small + .dropdown-toggle { + *padding-top: 5px; + *padding-bottom: 4px; +} + +.btn-group > .btn-large + .dropdown-toggle { + *padding-top: 7px; + padding-right: 12px; + *padding-bottom: 7px; + padding-left: 12px; +} + +.btn-group.open .dropdown-toggle { + background-image: none; + -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15), 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.btn-group.open .btn.dropdown-toggle { + background-color: #e6e6e6; +} + +.btn-group.open .btn-primary.dropdown-toggle { + background-color: #0044cc; +} + +.btn-group.open .btn-warning.dropdown-toggle { + background-color: #f89406; +} + +.btn-group.open .btn-danger.dropdown-toggle { + background-color: #bd362f; +} + +.btn-group.open .btn-success.dropdown-toggle { + background-color: #51a351; +} + +.btn-group.open .btn-info.dropdown-toggle { + background-color: #2f96b4; +} + +.btn-group.open .btn-inverse.dropdown-toggle { + background-color: #222222; +} + +.btn .caret { + margin-top: 8px; + margin-left: 0; +} + +.btn-large .caret { + margin-top: 6px; +} + +.btn-large .caret { + border-top-width: 5px; + border-right-width: 5px; + border-left-width: 5px; +} + +.btn-mini .caret, +.btn-small .caret { + margin-top: 8px; +} + +.dropup .btn-large .caret { + border-bottom-width: 5px; +} + +.btn-primary .caret, +.btn-warning .caret, +.btn-danger .caret, +.btn-info .caret, +.btn-success .caret, +.btn-inverse .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.btn-group-vertical { + display: inline-block; + *display: inline; + /* IE7 inline-block hack */ + + *zoom: 1; +} + +.btn-group-vertical > .btn { + display: block; + float: none; + max-width: 100%; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.btn-group-vertical > .btn + .btn { + margin-top: -1px; + margin-left: 0; +} + +.btn-group-vertical > .btn:first-child { + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.btn-group-vertical > .btn:last-child { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.btn-group-vertical > .btn-large:first-child { + -webkit-border-radius: 6px 6px 0 0; + -moz-border-radius: 6px 6px 0 0; + border-radius: 6px 6px 0 0; +} + +.btn-group-vertical > .btn-large:last-child { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.alert { + padding: 8px 35px 8px 14px; + margin-bottom: 20px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + background-color: #fcf8e3; + border: 1px solid #fbeed5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.alert, +.alert h4 { + color: #c09853; +} + +.alert h4 { + margin: 0; +} + +.alert .close { + position: relative; + top: -2px; + right: -21px; + line-height: 20px; +} + +.alert-success { + color: #468847; + background-color: #dff0d8; + border-color: #d6e9c6; +} + +.alert-success h4 { + color: #468847; +} + +.alert-danger, +.alert-error { + color: #b94a48; + background-color: #f2dede; + border-color: #eed3d7; +} + +.alert-danger h4, +.alert-error h4 { + color: #b94a48; +} + +.alert-info { + color: #3a87ad; + background-color: #d9edf7; + border-color: #bce8f1; +} + +.alert-info h4 { + color: #3a87ad; +} + +.alert-block { + padding-top: 14px; + padding-bottom: 14px; +} + +.alert-block > p, +.alert-block > ul { + margin-bottom: 0; +} + +.alert-block p + p { + margin-top: 5px; +} + +.nav { + margin-bottom: 20px; + margin-left: 0; + list-style: none; +} + +.nav > li > a { + display: block; +} + +.nav > li > a:hover, +.nav > li > a:focus { + text-decoration: none; + background-color: #eeeeee; +} + +.nav > li > a > img { + max-width: none; +} + +.nav > .pull-right { + float: right; +} + +.nav-header { + display: block; + padding: 3px 15px; + font-size: 11px; + font-weight: bold; + line-height: 20px; + color: #999999; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-transform: uppercase; +} + +.nav li + .nav-header { + margin-top: 9px; +} + +.nav-list { + padding-right: 15px; + padding-left: 15px; + margin-bottom: 0; +} + +.nav-list > li > a, +.nav-list .nav-header { + margin-right: -15px; + margin-left: -15px; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); +} + +.nav-list > li > a { + padding: 3px 15px; +} + +.nav-list > .active > a, +.nav-list > .active > a:hover, +.nav-list > .active > a:focus { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2); + background-color: #0088cc; +} + +.nav-list [class^="icon-"], +.nav-list [class*=" icon-"] { + margin-right: 2px; +} + +.nav-list .divider { + *width: 100%; + height: 1px; + margin: 9px 1px; + *margin: -5px 0 5px; + overflow: hidden; + background-color: #e5e5e5; + border-bottom: 1px solid #ffffff; +} + +.nav-tabs, +.nav-pills { + *zoom: 1; +} + +.nav-tabs:before, +.nav-pills:before, +.nav-tabs:after, +.nav-pills:after { + display: table; + line-height: 0; + content: ""; +} + +.nav-tabs:after, +.nav-pills:after { + clear: both; +} + +.nav-tabs > li, +.nav-pills > li { + float: left; +} + +.nav-tabs > li > a, +.nav-pills > li > a { + padding-right: 12px; + padding-left: 12px; + margin-right: 2px; + line-height: 14px; +} + +.nav-tabs { + border-bottom: 1px solid #ddd; +} + +.nav-tabs > li { + margin-bottom: -1px; +} + +.nav-tabs > li > a { + padding-top: 8px; + padding-bottom: 8px; + line-height: 20px; + border: 1px solid transparent; + -webkit-border-radius: 4px 4px 0 0; + -moz-border-radius: 4px 4px 0 0; + border-radius: 4px 4px 0 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #dddddd; +} + +.nav-tabs > .active > a, +.nav-tabs > .active > a:hover, +.nav-tabs > .active > a:focus { + color: #555555; + cursor: default; + background-color: #ffffff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} + +.nav-pills > li > a { + padding-top: 8px; + padding-bottom: 8px; + margin-top: 2px; + margin-bottom: 2px; + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + border-radius: 5px; +} + +.nav-pills > .active > a, +.nav-pills > .active > a:hover, +.nav-pills > .active > a:focus { + color: #ffffff; + background-color: #0088cc; +} + +.nav-stacked > li { + float: none; +} + +.nav-stacked > li > a { + margin-right: 0; +} + +.nav-tabs.nav-stacked { + border-bottom: 0; +} + +.nav-tabs.nav-stacked > li > a { + border: 1px solid #ddd; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.nav-tabs.nav-stacked > li:first-child > a { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; +} + +.nav-tabs.nav-stacked > li:last-child > a { + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-bottomright: 4px; + -moz-border-radius-bottomleft: 4px; +} + +.nav-tabs.nav-stacked > li > a:hover, +.nav-tabs.nav-stacked > li > a:focus { + z-index: 2; + border-color: #ddd; +} + +.nav-pills.nav-stacked > li > a { + margin-bottom: 3px; +} + +.nav-pills.nav-stacked > li:last-child > a { + margin-bottom: 1px; +} + +.nav-tabs .dropdown-menu { + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; +} + +.nav-pills .dropdown-menu { + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.nav .dropdown-toggle .caret { + margin-top: 6px; + border-top-color: #0088cc; + border-bottom-color: #0088cc; +} + +.nav .dropdown-toggle:hover .caret, +.nav .dropdown-toggle:focus .caret { + border-top-color: #005580; + border-bottom-color: #005580; +} + +/* move down carets for tabs */ + +.nav-tabs .dropdown-toggle .caret { + margin-top: 8px; +} + +.nav .active .dropdown-toggle .caret { + border-top-color: #fff; + border-bottom-color: #fff; +} + +.nav-tabs .active .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.nav > .dropdown.active > a:hover, +.nav > .dropdown.active > a:focus { + cursor: pointer; +} + +.nav-tabs .open .dropdown-toggle, +.nav-pills .open .dropdown-toggle, +.nav > li.dropdown.open.active > a:hover, +.nav > li.dropdown.open.active > a:focus { + color: #ffffff; + background-color: #999999; + border-color: #999999; +} + +.nav li.dropdown.open .caret, +.nav li.dropdown.open.active .caret, +.nav li.dropdown.open a:hover .caret, +.nav li.dropdown.open a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; + opacity: 1; + filter: alpha(opacity=100); +} + +.tabs-stacked .open > a:hover, +.tabs-stacked .open > a:focus { + border-color: #999999; +} + +.tabbable { + *zoom: 1; +} + +.tabbable:before, +.tabbable:after { + display: table; + line-height: 0; + content: ""; +} + +.tabbable:after { + clear: both; +} + +.tab-content { + overflow: auto; +} + +.tabs-below > .nav-tabs, +.tabs-right > .nav-tabs, +.tabs-left > .nav-tabs { + border-bottom: 0; +} + +.tab-content > .tab-pane, +.pill-content > .pill-pane { + display: none; +} + +.tab-content > .active, +.pill-content > .active { + display: block; +} + +.tabs-below > .nav-tabs { + border-top: 1px solid #ddd; +} + +.tabs-below > .nav-tabs > li { + margin-top: -1px; + margin-bottom: 0; +} + +.tabs-below > .nav-tabs > li > a { + -webkit-border-radius: 0 0 4px 4px; + -moz-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; +} + +.tabs-below > .nav-tabs > li > a:hover, +.tabs-below > .nav-tabs > li > a:focus { + border-top-color: #ddd; + border-bottom-color: transparent; +} + +.tabs-below > .nav-tabs > .active > a, +.tabs-below > .nav-tabs > .active > a:hover, +.tabs-below > .nav-tabs > .active > a:focus { + border-color: transparent #ddd #ddd #ddd; +} + +.tabs-left > .nav-tabs > li, +.tabs-right > .nav-tabs > li { + float: none; +} + +.tabs-left > .nav-tabs > li > a, +.tabs-right > .nav-tabs > li > a { + min-width: 74px; + margin-right: 0; + margin-bottom: 3px; +} + +.tabs-left > .nav-tabs { + float: left; + margin-right: 19px; + border-right: 1px solid #ddd; +} + +.tabs-left > .nav-tabs > li > a { + margin-right: -1px; + -webkit-border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} + +.tabs-left > .nav-tabs > li > a:hover, +.tabs-left > .nav-tabs > li > a:focus { + border-color: #eeeeee #dddddd #eeeeee #eeeeee; +} + +.tabs-left > .nav-tabs .active > a, +.tabs-left > .nav-tabs .active > a:hover, +.tabs-left > .nav-tabs .active > a:focus { + border-color: #ddd transparent #ddd #ddd; + *border-right-color: #ffffff; +} + +.tabs-right > .nav-tabs { + float: right; + margin-left: 19px; + border-left: 1px solid #ddd; +} + +.tabs-right > .nav-tabs > li > a { + margin-left: -1px; + -webkit-border-radius: 0 4px 4px 0; + -moz-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} + +.tabs-right > .nav-tabs > li > a:hover, +.tabs-right > .nav-tabs > li > a:focus { + border-color: #eeeeee #eeeeee #eeeeee #dddddd; +} + +.tabs-right > .nav-tabs .active > a, +.tabs-right > .nav-tabs .active > a:hover, +.tabs-right > .nav-tabs .active > a:focus { + border-color: #ddd #ddd #ddd transparent; + *border-left-color: #ffffff; +} + +.nav > .disabled > a { + color: #999999; +} + +.nav > .disabled > a:hover, +.nav > .disabled > a:focus { + text-decoration: none; + cursor: default; + background-color: transparent; +} + +.navbar { + *position: relative; + *z-index: 2; + margin-bottom: 20px; + overflow: visible; +} + +.navbar-inner { + min-height: 40px; + padding-right: 20px; + padding-left: 20px; + background-color: #fafafa; + background-image: -moz-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2)); + background-image: -webkit-linear-gradient(top, #ffffff, #f2f2f2); + background-image: -o-linear-gradient(top, #ffffff, #f2f2f2); + background-image: linear-gradient(to bottom, #ffffff, #f2f2f2); + background-repeat: repeat-x; + border: 1px solid #d4d4d4; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0); + *zoom: 1; + -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.065); +} + +.navbar-inner:before, +.navbar-inner:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-inner:after { + clear: both; +} + +.navbar .container { + width: auto; +} + +.nav-collapse.collapse { + height: auto; + overflow: visible; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: #777777; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .brand:hover, +.navbar .brand:focus { + text-decoration: none; +} + +.navbar-text { + margin-bottom: 0; + line-height: 40px; + color: #777777; +} + +.navbar-link { + color: #777777; +} + +.navbar-link:hover, +.navbar-link:focus { + color: #333333; +} + +.navbar .divider-vertical { + height: 40px; + margin: 0 9px; + border-right: 1px solid #ffffff; + border-left: 1px solid #f2f2f2; +} + +.navbar .btn, +.navbar .btn-group { + margin-top: 5px; +} + +.navbar .btn-group .btn, +.navbar .input-prepend .btn, +.navbar .input-append .btn, +.navbar .input-prepend .btn-group, +.navbar .input-append .btn-group { + margin-top: 0; +} + +.navbar-form { + margin-bottom: 0; + *zoom: 1; +} + +.navbar-form:before, +.navbar-form:after { + display: table; + line-height: 0; + content: ""; +} + +.navbar-form:after { + clear: both; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .radio, +.navbar-form .checkbox { + margin-top: 5px; +} + +.navbar-form input, +.navbar-form select, +.navbar-form .btn { + display: inline-block; + margin-bottom: 0; +} + +.navbar-form input[type="image"], +.navbar-form input[type="checkbox"], +.navbar-form input[type="radio"] { + margin-top: 3px; +} + +.navbar-form .input-append, +.navbar-form .input-prepend { + margin-top: 5px; + white-space: nowrap; +} + +.navbar-form .input-append input, +.navbar-form .input-prepend input { + margin-top: 0; +} + +.navbar-search { + position: relative; + float: left; + margin-top: 5px; + margin-bottom: 0; +} + +.navbar-search .search-query { + padding: 4px 14px; + margin-bottom: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 13px; + font-weight: normal; + line-height: 1; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.navbar-static-top { + position: static; + margin-bottom: 0; +} + +.navbar-static-top .navbar-inner { + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-fixed-top, +.navbar-fixed-bottom { + position: fixed; + right: 0; + left: 0; + z-index: 1030; + margin-bottom: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + border-width: 0 0 1px; +} + +.navbar-fixed-bottom .navbar-inner { + border-width: 1px 0 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-fixed-bottom .navbar-inner { + padding-right: 0; + padding-left: 0; + -webkit-border-radius: 0; + -moz-border-radius: 0; + border-radius: 0; +} + +.navbar-static-top .container, +.navbar-fixed-top .container, +.navbar-fixed-bottom .container { + width: 940px; +} + +.navbar-fixed-top { + top: 0; +} + +.navbar-fixed-top .navbar-inner, +.navbar-static-top .navbar-inner { + -webkit-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar-fixed-bottom { + bottom: 0; +} + +.navbar-fixed-bottom .navbar-inner { + -webkit-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + -moz-box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); + box-shadow: 0 -1px 10px rgba(0, 0, 0, 0.1); +} + +.navbar .nav { + position: relative; + left: 0; + display: block; + float: left; + margin: 0 10px 0 0; +} + +.navbar .nav.pull-right { + float: right; + margin-right: 0; +} + +.navbar .nav > li { + float: left; +} + +.navbar .nav > li > a { + float: none; + padding: 10px 15px 10px; + color: #777777; + text-decoration: none; + text-shadow: 0 1px 0 #ffffff; +} + +.navbar .nav .dropdown-toggle .caret { + margin-top: 8px; +} + +.navbar .nav > li > a:focus, +.navbar .nav > li > a:hover { + color: #333333; + text-decoration: none; + background-color: transparent; +} + +.navbar .nav > .active > a, +.navbar .nav > .active > a:hover, +.navbar .nav > .active > a:focus { + color: #555555; + text-decoration: none; + background-color: #e5e5e5; + -webkit-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + -moz-box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.125); +} + +.navbar .btn-navbar { + display: none; + float: right; + padding: 7px 10px; + margin-right: 5px; + margin-left: 5px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #ededed; + *background-color: #e5e5e5; + background-image: -moz-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5)); + background-image: -webkit-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: -o-linear-gradient(top, #f2f2f2, #e5e5e5); + background-image: linear-gradient(to bottom, #f2f2f2, #e5e5e5); + background-repeat: repeat-x; + border-color: #e5e5e5 #e5e5e5 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 0 rgba(255, 255, 255, 0.075); +} + +.navbar .btn-navbar:hover, +.navbar .btn-navbar:focus, +.navbar .btn-navbar:active, +.navbar .btn-navbar.active, +.navbar .btn-navbar.disabled, +.navbar .btn-navbar[disabled] { + color: #ffffff; + background-color: #e5e5e5; + *background-color: #d9d9d9; +} + +.navbar .btn-navbar:active, +.navbar .btn-navbar.active { + background-color: #cccccc \9; +} + +.navbar .btn-navbar .icon-bar { + display: block; + width: 18px; + height: 2px; + background-color: #f5f5f5; + -webkit-border-radius: 1px; + -moz-border-radius: 1px; + border-radius: 1px; + -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); + box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25); +} + +.btn-navbar .icon-bar + .icon-bar { + margin-top: 3px; +} + +.navbar .nav > li > .dropdown-menu:before { + position: absolute; + top: -7px; + left: 9px; + display: inline-block; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-left: 7px solid transparent; + border-bottom-color: rgba(0, 0, 0, 0.2); + content: ''; +} + +.navbar .nav > li > .dropdown-menu:after { + position: absolute; + top: -6px; + left: 10px; + display: inline-block; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + border-left: 6px solid transparent; + content: ''; +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:before { + top: auto; + bottom: -7px; + border-top: 7px solid #ccc; + border-bottom: 0; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.navbar-fixed-bottom .nav > li > .dropdown-menu:after { + top: auto; + bottom: -6px; + border-top: 6px solid #ffffff; + border-bottom: 0; +} + +.navbar .nav li.dropdown > a:hover .caret, +.navbar .nav li.dropdown > a:focus .caret { + border-top-color: #333333; + border-bottom-color: #333333; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle, +.navbar .nav li.dropdown.active > .dropdown-toggle, +.navbar .nav li.dropdown.open.active > .dropdown-toggle { + color: #555555; + background-color: #e5e5e5; +} + +.navbar .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #777777; + border-bottom-color: #777777; +} + +.navbar .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #555555; + border-bottom-color: #555555; +} + +.navbar .pull-right > li > .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right { + right: 0; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:before, +.navbar .nav > li > .dropdown-menu.pull-right:before { + right: 12px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu:after, +.navbar .nav > li > .dropdown-menu.pull-right:after { + right: 13px; + left: auto; +} + +.navbar .pull-right > li > .dropdown-menu .dropdown-menu, +.navbar .nav > li > .dropdown-menu.pull-right .dropdown-menu { + right: 100%; + left: auto; + margin-right: -1px; + margin-left: 0; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} + +.navbar-inverse .navbar-inner { + background-color: #1b1b1b; + background-image: -moz-linear-gradient(top, #222222, #111111); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111)); + background-image: -webkit-linear-gradient(top, #222222, #111111); + background-image: -o-linear-gradient(top, #222222, #111111); + background-image: linear-gradient(to bottom, #222222, #111111); + background-repeat: repeat-x; + border-color: #252525; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0); +} + +.navbar-inverse .brand, +.navbar-inverse .nav > li > a { + color: #999999; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} + +.navbar-inverse .brand:hover, +.navbar-inverse .nav > li > a:hover, +.navbar-inverse .brand:focus, +.navbar-inverse .nav > li > a:focus { + color: #ffffff; +} + +.navbar-inverse .brand { + color: #999999; +} + +.navbar-inverse .navbar-text { + color: #999999; +} + +.navbar-inverse .nav > li > a:focus, +.navbar-inverse .nav > li > a:hover { + color: #ffffff; + background-color: transparent; +} + +.navbar-inverse .nav .active > a, +.navbar-inverse .nav .active > a:hover, +.navbar-inverse .nav .active > a:focus { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .navbar-link { + color: #999999; +} + +.navbar-inverse .navbar-link:hover, +.navbar-inverse .navbar-link:focus { + color: #ffffff; +} + +.navbar-inverse .divider-vertical { + border-right-color: #222222; + border-left-color: #111111; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle { + color: #ffffff; + background-color: #111111; +} + +.navbar-inverse .nav li.dropdown > a:hover .caret, +.navbar-inverse .nav li.dropdown > a:focus .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .nav li.dropdown > .dropdown-toggle .caret { + border-top-color: #999999; + border-bottom-color: #999999; +} + +.navbar-inverse .nav li.dropdown.open > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.active > .dropdown-toggle .caret, +.navbar-inverse .nav li.dropdown.open.active > .dropdown-toggle .caret { + border-top-color: #ffffff; + border-bottom-color: #ffffff; +} + +.navbar-inverse .navbar-search .search-query { + color: #ffffff; + background-color: #515151; + border-color: #111111; + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 1px 0 rgba(255, 255, 255, 0.15); + -webkit-transition: none; + -moz-transition: none; + -o-transition: none; + transition: none; +} + +.navbar-inverse .navbar-search .search-query:-moz-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder { + color: #cccccc; +} + +.navbar-inverse .navbar-search .search-query:focus, +.navbar-inverse .navbar-search .search-query.focused { + padding: 5px 15px; + color: #333333; + text-shadow: 0 1px 0 #ffffff; + background-color: #ffffff; + border: 0; + outline: 0; + -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + -moz-box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); + box-shadow: 0 0 3px rgba(0, 0, 0, 0.15); +} + +.navbar-inverse .btn-navbar { + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e0e0e; + *background-color: #040404; + background-image: -moz-linear-gradient(top, #151515, #040404); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404)); + background-image: -webkit-linear-gradient(top, #151515, #040404); + background-image: -o-linear-gradient(top, #151515, #040404); + background-image: linear-gradient(to bottom, #151515, #040404); + background-repeat: repeat-x; + border-color: #040404 #040404 #000000; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.navbar-inverse .btn-navbar:hover, +.navbar-inverse .btn-navbar:focus, +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active, +.navbar-inverse .btn-navbar.disabled, +.navbar-inverse .btn-navbar[disabled] { + color: #ffffff; + background-color: #040404; + *background-color: #000000; +} + +.navbar-inverse .btn-navbar:active, +.navbar-inverse .btn-navbar.active { + background-color: #000000 \9; +} + +.breadcrumb { + padding: 8px 15px; + margin: 0 0 20px; + list-style: none; + background-color: #f5f5f5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.breadcrumb > li { + display: inline-block; + *display: inline; + text-shadow: 0 1px 0 #ffffff; + *zoom: 1; +} + +.breadcrumb > li > .divider { + padding: 0 5px; + color: #ccc; +} + +.breadcrumb > .active { + color: #999999; +} + +.pagination { + margin: 20px 0; +} + +.pagination ul { + display: inline-block; + *display: inline; + margin-bottom: 0; + margin-left: 0; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + *zoom: 1; + -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); +} + +.pagination ul > li { + display: inline; +} + +.pagination ul > li > a, +.pagination ul > li > span { + float: left; + padding: 4px 12px; + line-height: 20px; + text-decoration: none; + background-color: #ffffff; + border: 1px solid #dddddd; + border-left-width: 0; +} + +.pagination ul > li > a:hover, +.pagination ul > li > a:focus, +.pagination ul > .active > a, +.pagination ul > .active > span { + background-color: #f5f5f5; +} + +.pagination ul > .active > a, +.pagination ul > .active > span { + color: #999999; + cursor: default; +} + +.pagination ul > .disabled > span, +.pagination ul > .disabled > a, +.pagination ul > .disabled > a:hover, +.pagination ul > .disabled > a:focus { + color: #999999; + cursor: default; + background-color: transparent; +} + +.pagination ul > li:first-child > a, +.pagination ul > li:first-child > span { + border-left-width: 1px; + -webkit-border-bottom-left-radius: 4px; + border-bottom-left-radius: 4px; + -webkit-border-top-left-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-topleft: 4px; +} + +.pagination ul > li:last-child > a, +.pagination ul > li:last-child > span { + -webkit-border-top-right-radius: 4px; + border-top-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-bottomright: 4px; +} + +.pagination-centered { + text-align: center; +} + +.pagination-right { + text-align: right; +} + +.pagination-large ul > li > a, +.pagination-large ul > li > span { + padding: 11px 19px; + font-size: 17.5px; +} + +.pagination-large ul > li:first-child > a, +.pagination-large ul > li:first-child > span { + -webkit-border-bottom-left-radius: 6px; + border-bottom-left-radius: 6px; + -webkit-border-top-left-radius: 6px; + border-top-left-radius: 6px; + -moz-border-radius-bottomleft: 6px; + -moz-border-radius-topleft: 6px; +} + +.pagination-large ul > li:last-child > a, +.pagination-large ul > li:last-child > span { + -webkit-border-top-right-radius: 6px; + border-top-right-radius: 6px; + -webkit-border-bottom-right-radius: 6px; + border-bottom-right-radius: 6px; + -moz-border-radius-topright: 6px; + -moz-border-radius-bottomright: 6px; +} + +.pagination-mini ul > li:first-child > a, +.pagination-small ul > li:first-child > a, +.pagination-mini ul > li:first-child > span, +.pagination-small ul > li:first-child > span { + -webkit-border-bottom-left-radius: 3px; + border-bottom-left-radius: 3px; + -webkit-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-topleft: 3px; +} + +.pagination-mini ul > li:last-child > a, +.pagination-small ul > li:last-child > a, +.pagination-mini ul > li:last-child > span, +.pagination-small ul > li:last-child > span { + -webkit-border-top-right-radius: 3px; + border-top-right-radius: 3px; + -webkit-border-bottom-right-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-bottomright: 3px; +} + +.pagination-small ul > li > a, +.pagination-small ul > li > span { + padding: 2px 10px; + font-size: 11.9px; +} + +.pagination-mini ul > li > a, +.pagination-mini ul > li > span { + padding: 0 6px; + font-size: 10.5px; +} + +.pager { + margin: 20px 0; + text-align: center; + list-style: none; + *zoom: 1; +} + +.pager:before, +.pager:after { + display: table; + line-height: 0; + content: ""; +} + +.pager:after { + clear: both; +} + +.pager li { + display: inline; +} + +.pager li > a, +.pager li > span { + display: inline-block; + padding: 5px 14px; + background-color: #fff; + border: 1px solid #ddd; + -webkit-border-radius: 15px; + -moz-border-radius: 15px; + border-radius: 15px; +} + +.pager li > a:hover, +.pager li > a:focus { + text-decoration: none; + background-color: #f5f5f5; +} + +.pager .next > a, +.pager .next > span { + float: right; +} + +.pager .previous > a, +.pager .previous > span { + float: left; +} + +.pager .disabled > a, +.pager .disabled > a:hover, +.pager .disabled > a:focus, +.pager .disabled > span { + color: #999999; + cursor: default; + background-color: #fff; +} + +.modal-backdrop { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1040; + background-color: #000000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop, +.modal-backdrop.fade.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.modal { + position: fixed; + top: 10%; + left: 50%; + z-index: 1050; + width: 560px; + margin-left: -280px; + background-color: #ffffff; + border: 1px solid #999; + border: 1px solid rgba(0, 0, 0, 0.3); + *border: 1px solid #999; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + outline: none; + -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3); + -webkit-background-clip: padding-box; + -moz-background-clip: padding-box; + background-clip: padding-box; +} + +.modal.fade { + top: -25%; + -webkit-transition: opacity 0.3s linear, top 0.3s ease-out; + -moz-transition: opacity 0.3s linear, top 0.3s ease-out; + -o-transition: opacity 0.3s linear, top 0.3s ease-out; + transition: opacity 0.3s linear, top 0.3s ease-out; +} + +.modal.fade.in { + top: 10%; +} + +.modal-header { + padding: 9px 15px; + border-bottom: 1px solid #eee; +} + +.modal-header .close { + margin-top: 2px; +} + +.modal-header h3 { + margin: 0; + line-height: 30px; +} + +.modal-body { + position: relative; + max-height: 400px; + padding: 15px; + overflow-y: auto; +} + +.modal-form { + margin-bottom: 0; +} + +.modal-footer { + padding: 14px 15px 15px; + margin-bottom: 0; + text-align: right; + background-color: #f5f5f5; + border-top: 1px solid #ddd; + -webkit-border-radius: 0 0 6px 6px; + -moz-border-radius: 0 0 6px 6px; + border-radius: 0 0 6px 6px; + *zoom: 1; + -webkit-box-shadow: inset 0 1px 0 #ffffff; + -moz-box-shadow: inset 0 1px 0 #ffffff; + box-shadow: inset 0 1px 0 #ffffff; +} + +.modal-footer:before, +.modal-footer:after { + display: table; + line-height: 0; + content: ""; +} + +.modal-footer:after { + clear: both; +} + +.modal-footer .btn + .btn { + margin-bottom: 0; + margin-left: 5px; +} + +.modal-footer .btn-group .btn + .btn { + margin-left: -1px; +} + +.modal-footer .btn-block + .btn-block { + margin-left: 0; +} + +.tooltip { + position: absolute; + z-index: 1030; + display: block; + font-size: 11px; + line-height: 1.4; + opacity: 0; + filter: alpha(opacity=0); + visibility: visible; +} + +.tooltip.in { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.tooltip.top { + padding: 5px 0; + margin-top: -3px; +} + +.tooltip.right { + padding: 0 5px; + margin-left: 3px; +} + +.tooltip.bottom { + padding: 5px 0; + margin-top: 3px; +} + +.tooltip.left { + padding: 0 5px; + margin-left: -3px; +} + +.tooltip-inner { + max-width: 200px; + padding: 8px; + color: #ffffff; + text-align: center; + text-decoration: none; + background-color: #000000; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.tooltip-arrow { + position: absolute; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.tooltip.top .tooltip-arrow { + bottom: 0; + left: 50%; + margin-left: -5px; + border-top-color: #000000; + border-width: 5px 5px 0; +} + +.tooltip.right .tooltip-arrow { + top: 50%; + left: 0; + margin-top: -5px; + border-right-color: #000000; + border-width: 5px 5px 5px 0; +} + +.tooltip.left .tooltip-arrow { + top: 50%; + right: 0; + margin-top: -5px; + border-left-color: #000000; + border-width: 5px 0 5px 5px; +} + +.tooltip.bottom .tooltip-arrow { + top: 0; + left: 50%; + margin-left: -5px; + border-bottom-color: #000000; + border-width: 0 5px 5px; +} + +.popover { + position: absolute; + top: 0; + left: 0; + z-index: 1010; + display: none; + max-width: 276px; + padding: 1px; + text-align: left; + white-space: normal; + background-color: #ffffff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.2); + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; + -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); + -webkit-background-clip: padding-box; + -moz-background-clip: padding; + background-clip: padding-box; +} + +.popover.top { + margin-top: -10px; +} + +.popover.right { + margin-left: 10px; +} + +.popover.bottom { + margin-top: 10px; +} + +.popover.left { + margin-left: -10px; +} + +.popover-title { + padding: 8px 14px; + margin: 0; + font-size: 14px; + font-weight: normal; + line-height: 18px; + background-color: #f7f7f7; + border-bottom: 1px solid #ebebeb; + -webkit-border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + border-radius: 5px 5px 0 0; +} + +.popover-title:empty { + display: none; +} + +.popover-content { + padding: 9px 14px; +} + +.popover .arrow, +.popover .arrow:after { + position: absolute; + display: block; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; +} + +.popover .arrow { + border-width: 11px; +} + +.popover .arrow:after { + border-width: 10px; + content: ""; +} + +.popover.top .arrow { + bottom: -11px; + left: 50%; + margin-left: -11px; + border-top-color: #999; + border-top-color: rgba(0, 0, 0, 0.25); + border-bottom-width: 0; +} + +.popover.top .arrow:after { + bottom: 1px; + margin-left: -10px; + border-top-color: #ffffff; + border-bottom-width: 0; +} + +.popover.right .arrow { + top: 50%; + left: -11px; + margin-top: -11px; + border-right-color: #999; + border-right-color: rgba(0, 0, 0, 0.25); + border-left-width: 0; +} + +.popover.right .arrow:after { + bottom: -10px; + left: 1px; + border-right-color: #ffffff; + border-left-width: 0; +} + +.popover.bottom .arrow { + top: -11px; + left: 50%; + margin-left: -11px; + border-bottom-color: #999; + border-bottom-color: rgba(0, 0, 0, 0.25); + border-top-width: 0; +} + +.popover.bottom .arrow:after { + top: 1px; + margin-left: -10px; + border-bottom-color: #ffffff; + border-top-width: 0; +} + +.popover.left .arrow { + top: 50%; + right: -11px; + margin-top: -11px; + border-left-color: #999; + border-left-color: rgba(0, 0, 0, 0.25); + border-right-width: 0; +} + +.popover.left .arrow:after { + right: 1px; + bottom: -10px; + border-left-color: #ffffff; + border-right-width: 0; +} + +.thumbnails { + margin-left: -20px; + list-style: none; + *zoom: 1; +} + +.thumbnails:before, +.thumbnails:after { + display: table; + line-height: 0; + content: ""; +} + +.thumbnails:after { + clear: both; +} + +.row-fluid .thumbnails { + margin-left: 0; +} + +.thumbnails > li { + float: left; + margin-bottom: 20px; + margin-left: 20px; +} + +.thumbnail { + display: block; + padding: 4px; + line-height: 20px; + border: 1px solid #ddd; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.055); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} + +a.thumbnail:hover, +a.thumbnail:focus { + border-color: #0088cc; + -webkit-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + -moz-box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); + box-shadow: 0 1px 4px rgba(0, 105, 214, 0.25); +} + +.thumbnail > img { + display: block; + max-width: 100%; + margin-right: auto; + margin-left: auto; +} + +.thumbnail .caption { + padding: 9px; + color: #555555; +} + +.media, +.media-body { + overflow: hidden; + *overflow: visible; + zoom: 1; +} + +.media, +.media .media { + margin-top: 15px; +} + +.media:first-child { + margin-top: 0; +} + +.media-object { + display: block; +} + +.media-heading { + margin: 0 0 5px; +} + +.media > .pull-left { + margin-right: 10px; +} + +.media > .pull-right { + margin-left: 10px; +} + +.media-list { + margin-left: 0; + list-style: none; +} + +.label, +.badge { + display: inline-block; + padding: 2px 4px; + font-size: 11.844px; + font-weight: bold; + line-height: 14px; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + white-space: nowrap; + vertical-align: baseline; + background-color: #999999; +} + +.label { + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + border-radius: 3px; +} + +.badge { + padding-right: 9px; + padding-left: 9px; + -webkit-border-radius: 9px; + -moz-border-radius: 9px; + border-radius: 9px; +} + +.label:empty, +.badge:empty { + display: none; +} + +a.label:hover, +a.label:focus, +a.badge:hover, +a.badge:focus { + color: #ffffff; + text-decoration: none; + cursor: pointer; +} + +.label-important, +.badge-important { + background-color: #b94a48; +} + +.label-important[href], +.badge-important[href] { + background-color: #953b39; +} + +.label-warning, +.badge-warning { + background-color: #f89406; +} + +.label-warning[href], +.badge-warning[href] { + background-color: #c67605; +} + +.label-success, +.badge-success { + background-color: #468847; +} + +.label-success[href], +.badge-success[href] { + background-color: #356635; +} + +.label-info, +.badge-info { + background-color: #3a87ad; +} + +.label-info[href], +.badge-info[href] { + background-color: #2d6987; +} + +.label-inverse, +.badge-inverse { + background-color: #333333; +} + +.label-inverse[href], +.badge-inverse[href] { + background-color: #1a1a1a; +} + +.btn .label, +.btn .badge { + position: relative; + top: -1px; +} + +.btn-mini .label, +.btn-mini .badge { + top: 0; +} + +@-webkit-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-moz-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-ms-keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +@-o-keyframes progress-bar-stripes { + from { + background-position: 0 0; + } + to { + background-position: 40px 0; + } +} + +@keyframes progress-bar-stripes { + from { + background-position: 40px 0; + } + to { + background-position: 0 0; + } +} + +.progress { + height: 20px; + margin-bottom: 20px; + overflow: hidden; + background-color: #f7f7f7; + background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9)); + background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9); + background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9); + background-repeat: repeat-x; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0); + -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); + box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1); +} + +.progress .bar { + float: left; + width: 0; + height: 100%; + font-size: 12px; + color: #ffffff; + text-align: center; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + background-color: #0e90d2; + background-image: -moz-linear-gradient(top, #149bdf, #0480be); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be)); + background-image: -webkit-linear-gradient(top, #149bdf, #0480be); + background-image: -o-linear-gradient(top, #149bdf, #0480be); + background-image: linear-gradient(to bottom, #149bdf, #0480be); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0); + -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + -webkit-transition: width 0.6s ease; + -moz-transition: width 0.6s ease; + -o-transition: width 0.6s ease; + transition: width 0.6s ease; +} + +.progress .bar + .bar { + -webkit-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + -moz-box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); + box-shadow: inset 1px 0 0 rgba(0, 0, 0, 0.15), inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.progress-striped .bar { + background-color: #149bdf; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + -webkit-background-size: 40px 40px; + -moz-background-size: 40px 40px; + -o-background-size: 40px 40px; + background-size: 40px 40px; +} + +.progress.active .bar { + -webkit-animation: progress-bar-stripes 2s linear infinite; + -moz-animation: progress-bar-stripes 2s linear infinite; + -ms-animation: progress-bar-stripes 2s linear infinite; + -o-animation: progress-bar-stripes 2s linear infinite; + animation: progress-bar-stripes 2s linear infinite; +} + +.progress-danger .bar, +.progress .bar-danger { + background-color: #dd514c; + background-image: -moz-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35)); + background-image: -webkit-linear-gradient(top, #ee5f5b, #c43c35); + background-image: -o-linear-gradient(top, #ee5f5b, #c43c35); + background-image: linear-gradient(to bottom, #ee5f5b, #c43c35); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0); +} + +.progress-danger.progress-striped .bar, +.progress-striped .bar-danger { + background-color: #ee5f5b; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-success .bar, +.progress .bar-success { + background-color: #5eb95e; + background-image: -moz-linear-gradient(top, #62c462, #57a957); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957)); + background-image: -webkit-linear-gradient(top, #62c462, #57a957); + background-image: -o-linear-gradient(top, #62c462, #57a957); + background-image: linear-gradient(to bottom, #62c462, #57a957); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0); +} + +.progress-success.progress-striped .bar, +.progress-striped .bar-success { + background-color: #62c462; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-info .bar, +.progress .bar-info { + background-color: #4bb1cf; + background-image: -moz-linear-gradient(top, #5bc0de, #339bb9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9)); + background-image: -webkit-linear-gradient(top, #5bc0de, #339bb9); + background-image: -o-linear-gradient(top, #5bc0de, #339bb9); + background-image: linear-gradient(to bottom, #5bc0de, #339bb9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0); +} + +.progress-info.progress-striped .bar, +.progress-striped .bar-info { + background-color: #5bc0de; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-warning .bar, +.progress .bar-warning { + background-color: #faa732; + background-image: -moz-linear-gradient(top, #fbb450, #f89406); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406)); + background-image: -webkit-linear-gradient(top, #fbb450, #f89406); + background-image: -o-linear-gradient(top, #fbb450, #f89406); + background-image: linear-gradient(to bottom, #fbb450, #f89406); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0); +} + +.progress-warning.progress-striped .bar, +.progress-striped .bar-warning { + background-color: #fbb450; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.accordion { + margin-bottom: 20px; +} + +.accordion-group { + margin-bottom: 2px; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} + +.accordion-heading { + border-bottom: 0; +} + +.accordion-heading .accordion-toggle { + display: block; + padding: 8px 15px; +} + +.accordion-toggle { + cursor: pointer; +} + +.accordion-inner { + padding: 9px 15px; + border-top: 1px solid #e5e5e5; +} + +.carousel { + position: relative; + margin-bottom: 20px; + line-height: 1; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; +} + +.carousel-inner > .item { + position: relative; + display: none; + -webkit-transition: 0.6s ease-in-out left; + -moz-transition: 0.6s ease-in-out left; + -o-transition: 0.6s ease-in-out left; + transition: 0.6s ease-in-out left; +} + +.carousel-inner > .item > img, +.carousel-inner > .item > a > img { + display: block; + line-height: 1; +} + +.carousel-inner > .active, +.carousel-inner > .next, +.carousel-inner > .prev { + display: block; +} + +.carousel-inner > .active { + left: 0; +} + +.carousel-inner > .next, +.carousel-inner > .prev { + position: absolute; + top: 0; + width: 100%; +} + +.carousel-inner > .next { + left: 100%; +} + +.carousel-inner > .prev { + left: -100%; +} + +.carousel-inner > .next.left, +.carousel-inner > .prev.right { + left: 0; +} + +.carousel-inner > .active.left { + left: -100%; +} + +.carousel-inner > .active.right { + left: 100%; +} + +.carousel-control { + position: absolute; + top: 40%; + left: 15px; + width: 40px; + height: 40px; + margin-top: -20px; + font-size: 60px; + font-weight: 100; + line-height: 30px; + color: #ffffff; + text-align: center; + background: #222222; + border: 3px solid #ffffff; + -webkit-border-radius: 23px; + -moz-border-radius: 23px; + border-radius: 23px; + opacity: 0.5; + filter: alpha(opacity=50); +} + +.carousel-control.right { + right: 15px; + left: auto; +} + +.carousel-control:hover, +.carousel-control:focus { + color: #ffffff; + text-decoration: none; + opacity: 0.9; + filter: alpha(opacity=90); +} + +.carousel-indicators { + position: absolute; + top: 15px; + right: 15px; + z-index: 5; + margin: 0; + list-style: none; +} + +.carousel-indicators li { + display: block; + float: left; + width: 10px; + height: 10px; + margin-left: 5px; + text-indent: -999px; + background-color: #ccc; + background-color: rgba(255, 255, 255, 0.25); + border-radius: 5px; +} + +.carousel-indicators .active { + background-color: #fff; +} + +.carousel-caption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + padding: 15px; + background: #333333; + background: rgba(0, 0, 0, 0.75); +} + +.carousel-caption h4, +.carousel-caption p { + line-height: 20px; + color: #ffffff; +} + +.carousel-caption h4 { + margin: 0 0 5px; +} + +.carousel-caption p { + margin-bottom: 0; +} + +.hero-unit { + padding: 60px; + margin-bottom: 30px; + font-size: 18px; + font-weight: 200; + line-height: 30px; + color: inherit; + background-color: #eeeeee; + -webkit-border-radius: 6px; + -moz-border-radius: 6px; + border-radius: 6px; +} + +.hero-unit h1 { + margin-bottom: 0; + font-size: 60px; + line-height: 1; + letter-spacing: -1px; + color: inherit; +} + +.hero-unit li { + line-height: 30px; +} + +.pull-right { + float: right; +} + +.pull-left { + float: left; +} + +.hide { + display: none; +} + +.show { + display: block; +} + +.invisible { + visibility: hidden; +} + +.affix { + position: fixed; +} diff --git a/docs/_static/bootstrap-2.3.2/css/bootstrap.min.css b/docs/_static/bootstrap-2.3.2/css/bootstrap.min.css new file mode 100644 index 00000000..b6428e69 --- /dev/null +++ b/docs/_static/bootstrap-2.3.2/css/bootstrap.min.css @@ -0,0 +1,9 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */.clearfix{*zoom:1}.clearfix:before,.clearfix:after{display:table;line-height:0;content:""}.clearfix:after{clear:both}.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block}audio,canvas,video{display:inline-block;*display:inline;*zoom:1}audio:not([controls]){display:none}html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}a:hover,a:active{outline:0}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{width:auto\9;height:auto;max-width:100%;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic}#map_canvas img,.google-maps img{max-width:none}button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle}button,input{*overflow:visible;line-height:normal}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none}textarea{overflow:auto;vertical-align:top}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:.5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333;background-color:#fff}a{color:#08c;text-decoration:none}a:hover,a:focus{color:#005580;text-decoration:underline}.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.1);box-shadow:0 1px 3px rgba(0,0,0,0.1)}.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px}.row{margin-left:-20px;*zoom:1}.row:before,.row:after{display:table;line-height:0;content:""}.row:after{clear:both}[class*="span"]{float:left;min-height:1px;margin-left:20px}.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.span12{width:940px}.span11{width:860px}.span10{width:780px}.span9{width:700px}.span8{width:620px}.span7{width:540px}.span6{width:460px}.span5{width:380px}.span4{width:300px}.span3{width:220px}.span2{width:140px}.span1{width:60px}.offset12{margin-left:980px}.offset11{margin-left:900px}.offset10{margin-left:820px}.offset9{margin-left:740px}.offset8{margin-left:660px}.offset7{margin-left:580px}.offset6{margin-left:500px}.offset5{margin-left:420px}.offset4{margin-left:340px}.offset3{margin-left:260px}.offset2{margin-left:180px}.offset1{margin-left:100px}.row-fluid{width:100%;*zoom:1}.row-fluid:before,.row-fluid:after{display:table;line-height:0;content:""}.row-fluid:after{clear:both}.row-fluid [class*="span"]{display:block;float:left;width:100%;min-height:30px;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.row-fluid [class*="span"]:first-child{margin-left:0}.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%}.row-fluid .span12{width:100%;*width:99.94680851063829%}.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%}.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%}.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%}.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%}.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%}.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%}.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%}.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%}.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%}.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%}.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%}.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%}.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%}.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%}.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%}.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%}.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%}.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%}.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%}.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%}.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%}.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%}.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%}.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%}.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%}.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%}.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%}.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%}.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%}.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%}.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%}.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%}.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%}.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%}.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%}[class*="span"].hide,.row-fluid [class*="span"].hide{display:none}[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right}.container{margin-right:auto;margin-left:auto;*zoom:1}.container:before,.container:after{display:table;line-height:0;content:""}.container:after{clear:both}.container-fluid{padding-right:20px;padding-left:20px;*zoom:1}.container-fluid:before,.container-fluid:after{display:table;line-height:0;content:""}.container-fluid:after{clear:both}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px}small{font-size:85%}strong{font-weight:bold}em{font-style:italic}cite{font-style:normal}.muted{color:#999}a.muted:hover,a.muted:focus{color:#808080}.text-warning{color:#c09853}a.text-warning:hover,a.text-warning:focus{color:#a47e3c}.text-error{color:#b94a48}a.text-error:hover,a.text-error:focus{color:#953b39}.text-info{color:#3a87ad}a.text-info:hover,a.text-info:focus{color:#2d6987}.text-success{color:#468847}a.text-success:hover,a.text-success:focus{color:#356635}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{line-height:40px}h1{font-size:38.5px}h2{font-size:31.5px}h3{font-size:24.5px}h4{font-size:17.5px}h5{font-size:14px}h6{font-size:11.9px}h1 small{font-size:24.5px}h2 small{font-size:17.5px}h3 small{font-size:14px}h4 small{font-size:14px}.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eee}ul,ol{padding:0;margin:0 0 10px 25px}ul ul,ul ol,ol ol,ol ul{margin-bottom:0}li{line-height:20px}ul.unstyled,ol.unstyled{margin-left:0;list-style:none}ul.inline,ol.inline{margin-left:0;list-style:none}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;padding-right:5px;padding-left:5px;*zoom:1}dl{margin-bottom:20px}dt,dd{line-height:20px}dt{font-weight:bold}dd{margin-left:10px}.dl-horizontal{*zoom:1}.dl-horizontal:before,.dl-horizontal:after{display:table;line-height:0;content:""}.dl-horizontal:after{clear:both}.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}hr{margin:20px 0;border:0;border-top:1px solid #eee;border-bottom:1px solid #fff}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}abbr.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25}blockquote small{display:block;line-height:20px;color:#999}blockquote small:before{content:'\2014 \00A0'}blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small{text-align:right}blockquote.pull-right small:before{content:''}blockquote.pull-right small:after{content:'\00A0 \2014'}q:before,q:after,blockquote:before,blockquote:after{content:""}address{display:block;margin-bottom:20px;font-style:normal;line-height:20px}code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}code{padding:2px 4px;color:#d14;white-space:nowrap;background-color:#f7f7f9;border:1px solid #e1e1e8}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}pre.prettyprint{margin-bottom:20px}pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0}.pre-scrollable{max-height:340px;overflow-y:scroll}form{margin:0 0 20px}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333;border:0;border-bottom:1px solid #e5e5e5}legend small{font-size:15px;color:#999}label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px}input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}label{display:block;margin-bottom:5px}select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555;vertical-align:middle;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}input,textarea,.uneditable-input{width:206px}textarea{height:auto}textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#fff;border:1px solid #ccc;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border linear .2s,box-shadow linear .2s;-moz-transition:border linear .2s,box-shadow linear .2s;-o-transition:border linear .2s,box-shadow linear .2s;transition:border linear .2s,box-shadow linear .2s}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82,168,236,0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(82,168,236,0.6)}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;*margin-top:0;line-height:normal}input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto}select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px}select{width:220px;background-color:#fff;border:1px solid #ccc}select[multiple],select[size]{height:auto}select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.uneditable-input,.uneditable-textarea{color:#999;cursor:not-allowed;background-color:#fcfcfc;border-color:#ccc;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.025);box-shadow:inset 0 1px 2px rgba(0,0,0,0.025)}.uneditable-input{overflow:hidden;white-space:nowrap}.uneditable-textarea{width:auto;height:auto}input:-moz-placeholder,textarea:-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.radio,.checkbox{min-height:20px;padding-left:20px}.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px}.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px}.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle}.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px}.input-mini{width:60px}.input-small{width:90px}.input-medium{width:150px}.input-large{width:210px}.input-xlarge{width:270px}.input-xxlarge{width:530px}input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0}.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block}input,textarea,.uneditable-input{margin-left:0}.controls-row [class*="span"]+[class*="span"]{margin-left:20px}input.span12,textarea.span12,.uneditable-input.span12{width:926px}input.span11,textarea.span11,.uneditable-input.span11{width:846px}input.span10,textarea.span10,.uneditable-input.span10{width:766px}input.span9,textarea.span9,.uneditable-input.span9{width:686px}input.span8,textarea.span8,.uneditable-input.span8{width:606px}input.span7,textarea.span7,.uneditable-input.span7{width:526px}input.span6,textarea.span6,.uneditable-input.span6{width:446px}input.span5,textarea.span5,.uneditable-input.span5{width:366px}input.span4,textarea.span4,.uneditable-input.span4{width:286px}input.span3,textarea.span3,.uneditable-input.span3{width:206px}input.span2,textarea.span2,.uneditable-input.span2{width:126px}input.span1,textarea.span1,.uneditable-input.span1{width:46px}.controls-row{*zoom:1}.controls-row:before,.controls-row:after{display:table;line-height:0;content:""}.controls-row:after{clear:both}.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left}.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px}input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eee}input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent}.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853}.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853}.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48}.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48}.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847}.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847}.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847}.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad}.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad}.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7ab5d3}.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad}input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7}.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1}.form-actions:before,.form-actions:after{display:table;line-height:0;content:""}.form-actions:after{clear:both}.help-block,.help-inline{color:#595959}.help-block{display:block;margin-bottom:10px}.help-inline{display:inline-block;*display:inline;padding-left:5px;vertical-align:middle;*zoom:1}.input-append,.input-prepend{display:inline-block;margin-bottom:10px;font-size:0;white-space:nowrap;vertical-align:middle}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2}.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #fff;background-color:#eee;border:1px solid #ccc}.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546}.input-prepend .add-on,.input-prepend .btn{margin-right:-1px}.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px}.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.input-prepend.input-append .btn-group:first-child{margin-left:0}input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0}.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px}.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;margin-bottom:0;vertical-align:middle;*zoom:1}.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none}.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block}.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0}.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle}.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0}.control-group{margin-bottom:10px}legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate}.form-horizontal .control-group{margin-bottom:20px;*zoom:1}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;line-height:0;content:""}.form-horizontal .control-group:after{clear:both}.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right}.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0}.form-horizontal .controls:first-child{*padding-left:180px}.form-horizontal .help-block{margin-bottom:0}.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px}.form-horizontal .form-actions{padding-left:180px}table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0}.table{width:100%;margin-bottom:20px}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #ddd}.table th{font-weight:bold}.table thead th{vertical-align:bottom}.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0}.table tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed th,.table-condensed td{padding:4px 5px}.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.table-bordered th,.table-bordered td{border-left:1px solid #ddd}.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0}.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px}.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px}.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0;-moz-border-radius-bottomleft:0}.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-moz-border-radius-bottomright:0}.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px}.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px}.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5}table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0}.table td.span1,.table th.span1{float:none;width:44px;margin-left:0}.table td.span2,.table th.span2{float:none;width:124px;margin-left:0}.table td.span3,.table th.span3{float:none;width:204px;margin-left:0}.table td.span4,.table th.span4{float:none;width:284px;margin-left:0}.table td.span5,.table th.span5{float:none;width:364px;margin-left:0}.table td.span6,.table th.span6{float:none;width:444px;margin-left:0}.table td.span7,.table th.span7{float:none;width:524px;margin-left:0}.table td.span8,.table th.span8{float:none;width:604px;margin-left:0}.table td.span9,.table th.span9{float:none;width:684px;margin-left:0}.table td.span10,.table th.span10{float:none;width:764px;margin-left:0}.table td.span11,.table th.span11{float:none;width:844px;margin-left:0}.table td.span12,.table th.span12{float:none;width:924px;margin-left:0}.table tbody tr.success>td{background-color:#dff0d8}.table tbody tr.error>td{background-color:#f2dede}.table tbody tr.warning>td{background-color:#fcf8e3}.table tbody tr.info>td{background-color:#d9edf7}.table-hover tbody tr.success:hover>td{background-color:#d0e9c6}.table-hover tbody tr.error:hover>td{background-color:#ebcccc}.table-hover tbody tr.warning:hover>td{background-color:#faf2cc}.table-hover tbody tr.info:hover>td{background-color:#c4e3f3}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:focus>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>li>a:focus>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:focus>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"],.dropdown-submenu:focus>a>[class*=" icon-"]{background-image:url("../img/glyphicons-halflings-white.png")}.icon-glass{background-position:0 0}.icon-music{background-position:-24px 0}.icon-search{background-position:-48px 0}.icon-envelope{background-position:-72px 0}.icon-heart{background-position:-96px 0}.icon-star{background-position:-120px 0}.icon-star-empty{background-position:-144px 0}.icon-user{background-position:-168px 0}.icon-film{background-position:-192px 0}.icon-th-large{background-position:-216px 0}.icon-th{background-position:-240px 0}.icon-th-list{background-position:-264px 0}.icon-ok{background-position:-288px 0}.icon-remove{background-position:-312px 0}.icon-zoom-in{background-position:-336px 0}.icon-zoom-out{background-position:-360px 0}.icon-off{background-position:-384px 0}.icon-signal{background-position:-408px 0}.icon-cog{background-position:-432px 0}.icon-trash{background-position:-456px 0}.icon-home{background-position:0 -24px}.icon-file{background-position:-24px -24px}.icon-time{background-position:-48px -24px}.icon-road{background-position:-72px -24px}.icon-download-alt{background-position:-96px -24px}.icon-download{background-position:-120px -24px}.icon-upload{background-position:-144px -24px}.icon-inbox{background-position:-168px -24px}.icon-play-circle{background-position:-192px -24px}.icon-repeat{background-position:-216px -24px}.icon-refresh{background-position:-240px -24px}.icon-list-alt{background-position:-264px -24px}.icon-lock{background-position:-287px -24px}.icon-flag{background-position:-312px -24px}.icon-headphones{background-position:-336px -24px}.icon-volume-off{background-position:-360px -24px}.icon-volume-down{background-position:-384px -24px}.icon-volume-up{background-position:-408px -24px}.icon-qrcode{background-position:-432px -24px}.icon-barcode{background-position:-456px -24px}.icon-tag{background-position:0 -48px}.icon-tags{background-position:-25px -48px}.icon-book{background-position:-48px -48px}.icon-bookmark{background-position:-72px -48px}.icon-print{background-position:-96px -48px}.icon-camera{background-position:-120px -48px}.icon-font{background-position:-144px -48px}.icon-bold{background-position:-167px -48px}.icon-italic{background-position:-192px -48px}.icon-text-height{background-position:-216px -48px}.icon-text-width{background-position:-240px -48px}.icon-align-left{background-position:-264px -48px}.icon-align-center{background-position:-288px -48px}.icon-align-right{background-position:-312px -48px}.icon-align-justify{background-position:-336px -48px}.icon-list{background-position:-360px -48px}.icon-indent-left{background-position:-384px -48px}.icon-indent-right{background-position:-408px -48px}.icon-facetime-video{background-position:-432px -48px}.icon-picture{background-position:-456px -48px}.icon-pencil{background-position:0 -72px}.icon-map-marker{background-position:-24px -72px}.icon-adjust{background-position:-48px -72px}.icon-tint{background-position:-72px -72px}.icon-edit{background-position:-96px -72px}.icon-share{background-position:-120px -72px}.icon-check{background-position:-144px -72px}.icon-move{background-position:-168px -72px}.icon-step-backward{background-position:-192px -72px}.icon-fast-backward{background-position:-216px -72px}.icon-backward{background-position:-240px -72px}.icon-play{background-position:-264px -72px}.icon-pause{background-position:-288px -72px}.icon-stop{background-position:-312px -72px}.icon-forward{background-position:-336px -72px}.icon-fast-forward{background-position:-360px -72px}.icon-step-forward{background-position:-384px -72px}.icon-eject{background-position:-408px -72px}.icon-chevron-left{background-position:-432px -72px}.icon-chevron-right{background-position:-456px -72px}.icon-plus-sign{background-position:0 -96px}.icon-minus-sign{background-position:-24px -96px}.icon-remove-sign{background-position:-48px -96px}.icon-ok-sign{background-position:-72px -96px}.icon-question-sign{background-position:-96px -96px}.icon-info-sign{background-position:-120px -96px}.icon-screenshot{background-position:-144px -96px}.icon-remove-circle{background-position:-168px -96px}.icon-ok-circle{background-position:-192px -96px}.icon-ban-circle{background-position:-216px -96px}.icon-arrow-left{background-position:-240px -96px}.icon-arrow-right{background-position:-264px -96px}.icon-arrow-up{background-position:-289px -96px}.icon-arrow-down{background-position:-312px -96px}.icon-share-alt{background-position:-336px -96px}.icon-resize-full{background-position:-360px -96px}.icon-resize-small{background-position:-384px -96px}.icon-plus{background-position:-408px -96px}.icon-minus{background-position:-433px -96px}.icon-asterisk{background-position:-456px -96px}.icon-exclamation-sign{background-position:0 -120px}.icon-gift{background-position:-24px -120px}.icon-leaf{background-position:-48px -120px}.icon-fire{background-position:-72px -120px}.icon-eye-open{background-position:-96px -120px}.icon-eye-close{background-position:-120px -120px}.icon-warning-sign{background-position:-144px -120px}.icon-plane{background-position:-168px -120px}.icon-calendar{background-position:-192px -120px}.icon-random{width:16px;background-position:-216px -120px}.icon-comment{background-position:-240px -120px}.icon-magnet{background-position:-264px -120px}.icon-chevron-up{background-position:-288px -120px}.icon-chevron-down{background-position:-313px -119px}.icon-retweet{background-position:-336px -120px}.icon-shopping-cart{background-position:-360px -120px}.icon-folder-close{width:16px;background-position:-384px -120px}.icon-folder-open{width:16px;background-position:-408px -120px}.icon-resize-vertical{background-position:-432px -119px}.icon-resize-horizontal{background-position:-456px -118px}.icon-hdd{background-position:0 -144px}.icon-bullhorn{background-position:-24px -144px}.icon-bell{background-position:-48px -144px}.icon-certificate{background-position:-72px -144px}.icon-thumbs-up{background-position:-96px -144px}.icon-thumbs-down{background-position:-120px -144px}.icon-hand-right{background-position:-144px -144px}.icon-hand-left{background-position:-168px -144px}.icon-hand-up{background-position:-192px -144px}.icon-hand-down{background-position:-216px -144px}.icon-circle-arrow-right{background-position:-240px -144px}.icon-circle-arrow-left{background-position:-264px -144px}.icon-circle-arrow-up{background-position:-288px -144px}.icon-circle-arrow-down{background-position:-312px -144px}.icon-globe{background-position:-336px -144px}.icon-wrench{background-position:-360px -144px}.icon-tasks{background-position:-384px -144px}.icon-filter{background-position:-408px -144px}.icon-briefcase{background-position:-432px -144px}.icon-fullscreen{background-position:-456px -144px}.dropup,.dropdown{position:relative}.dropdown-toggle{*margin-bottom:-3px}.dropdown-toggle:active,.open .dropdown-toggle{outline:0}.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000;border-right:4px solid transparent;border-left:4px solid transparent;content:""}.dropdown .caret{margin-top:8px;margin-left:2px}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#0081c2;background-image:-moz-linear-gradient(top,#08c,#0077b3);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#0077b3));background-image:-webkit-linear-gradient(top,#08c,#0077b3);background-image:-o-linear-gradient(top,#08c,#0077b3);background-image:linear-gradient(to bottom,#08c,#0077b3);background-repeat:repeat-x;outline:0;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0077b3',GradientType=0)}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open{*z-index:1000}.open>.dropdown-menu{display:block}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}.dropdown-submenu{position:relative}.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover>.dropdown-menu{display:block}.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0}.dropdown-submenu>a:after{display:block;float:right;width:0;height:0;margin-top:5px;margin-right:-10px;border-color:transparent;border-left-color:#ccc;border-style:solid;border-width:5px 0 5px 5px;content:" "}.dropdown-submenu:hover>a:after{border-left-color:#fff}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.dropdown .dropdown-menu .nav-header{padding-right:20px;padding-left:20px}.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.fade{opacity:0;-webkit-transition:opacity .15s linear;-moz-transition:opacity .15s linear;-o-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;-moz-transition:height .35s ease;-o-transition:height .35s ease;transition:height .35s ease}.collapse.in{height:auto}.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.4;filter:alpha(opacity=40)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.btn{display:inline-block;*display:inline;padding:4px 12px;margin-bottom:0;*margin-left:.3em;font-size:14px;line-height:20px;color:#333;text-align:center;text-shadow:0 1px 1px rgba(255,255,255,0.75);vertical-align:middle;cursor:pointer;background-color:#f5f5f5;*background-color:#e6e6e6;background-image:-moz-linear-gradient(top,#fff,#e6e6e6);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#e6e6e6));background-image:-webkit-linear-gradient(top,#fff,#e6e6e6);background-image:-o-linear-gradient(top,#fff,#e6e6e6);background-image:linear-gradient(to bottom,#fff,#e6e6e6);background-repeat:repeat-x;border:1px solid #ccc;*border:0;border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#ffe6e6e6',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);*zoom:1;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333;background-color:#e6e6e6;*background-color:#d9d9d9}.btn:active,.btn.active{background-color:#ccc \9}.btn:first-child{*margin-left:0}.btn:hover,.btn:focus{color:#333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position .1s linear;-moz-transition:background-position .1s linear;-o-transition:background-position .1s linear;transition:background-position .1s linear}.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px}.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0}.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px}.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255,255,255,0.75)}.btn-primary{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#006dcc;*background-color:#04c;background-image:-moz-linear-gradient(top,#08c,#04c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#08c),to(#04c));background-image:-webkit-linear-gradient(top,#08c,#04c);background-image:-o-linear-gradient(top,#08c,#04c);background-image:linear-gradient(to bottom,#08c,#04c);background-repeat:repeat-x;border-color:#04c #04c #002a80;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc',endColorstr='#ff0044cc',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#fff;background-color:#04c;*background-color:#003bb3}.btn-primary:active,.btn-primary.active{background-color:#039 \9}.btn-warning{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#faa732;*background-color:#f89406;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;border-color:#f89406 #f89406 #ad6704;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#fff;background-color:#f89406;*background-color:#df8505}.btn-warning:active,.btn-warning.active{background-color:#c67605 \9}.btn-danger{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#da4f49;*background-color:#bd362f;background-image:-moz-linear-gradient(top,#ee5f5b,#bd362f);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#bd362f));background-image:-webkit-linear-gradient(top,#ee5f5b,#bd362f);background-image:-o-linear-gradient(top,#ee5f5b,#bd362f);background-image:linear-gradient(to bottom,#ee5f5b,#bd362f);background-repeat:repeat-x;border-color:#bd362f #bd362f #802420;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffbd362f',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#fff;background-color:#bd362f;*background-color:#a9302a}.btn-danger:active,.btn-danger.active{background-color:#942a25 \9}.btn-success{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#5bb75b;*background-color:#51a351;background-image:-moz-linear-gradient(top,#62c462,#51a351);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#51a351));background-image:-webkit-linear-gradient(top,#62c462,#51a351);background-image:-o-linear-gradient(top,#62c462,#51a351);background-image:linear-gradient(to bottom,#62c462,#51a351);background-repeat:repeat-x;border-color:#51a351 #51a351 #387038;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff51a351',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#fff;background-color:#51a351;*background-color:#499249}.btn-success:active,.btn-success.active{background-color:#408140 \9}.btn-info{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#49afcd;*background-color:#2f96b4;background-image:-moz-linear-gradient(top,#5bc0de,#2f96b4);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#2f96b4));background-image:-webkit-linear-gradient(top,#5bc0de,#2f96b4);background-image:-o-linear-gradient(top,#5bc0de,#2f96b4);background-image:linear-gradient(to bottom,#5bc0de,#2f96b4);background-repeat:repeat-x;border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff2f96b4',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#fff;background-color:#2f96b4;*background-color:#2a85a0}.btn-info:active,.btn-info.active{background-color:#24748c \9}.btn-inverse{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#363636;*background-color:#222;background-image:-moz-linear-gradient(top,#444,#222);background-image:-webkit-gradient(linear,0 0,0 100%,from(#444),to(#222));background-image:-webkit-linear-gradient(top,#444,#222);background-image:-o-linear-gradient(top,#444,#222);background-image:linear-gradient(to bottom,#444,#222);background-repeat:repeat-x;border-color:#222 #222 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444',endColorstr='#ff222222',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#fff;background-color:#222;*background-color:#151515}.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9}button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0}button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px}button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px}button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px}.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.btn-link{color:#08c;cursor:pointer;border-color:transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333;text-decoration:none}.btn-group{position:relative;display:inline-block;*display:inline;*margin-left:.3em;font-size:0;white-space:nowrap;vertical-align:middle;*zoom:1}.btn-group:first-child{*margin-left:0}.btn-group+.btn-group{margin-left:5px}.btn-toolbar{margin-top:10px;margin-bottom:10px;font-size:0}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px}.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group>.btn+.btn{margin-left:-1px}.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px}.btn-group>.btn-mini{font-size:10.5px}.btn-group>.btn-small{font-size:11.9px}.btn-group>.btn-large{font-size:17.5px}.btn-group>.btn:first-child{margin-left:0;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group>.btn+.dropdown-toggle{*padding-top:5px;padding-right:8px;*padding-bottom:5px;padding-left:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 1px 0 0 rgba(255,255,255,0.125),inset 0 1px 0 rgba(255,255,255,0.2),0 1px 2px rgba(0,0,0,0.05)}.btn-group>.btn-mini+.dropdown-toggle{*padding-top:2px;padding-right:5px;*padding-bottom:2px;padding-left:5px}.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px}.btn-group>.btn-large+.dropdown-toggle{*padding-top:7px;padding-right:12px;*padding-bottom:7px;padding-left:12px}.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);box-shadow:inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05)}.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6}.btn-group.open .btn-primary.dropdown-toggle{background-color:#04c}.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406}.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f}.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351}.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4}.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222}.btn .caret{margin-top:8px;margin-left:0}.btn-large .caret{margin-top:6px}.btn-large .caret{border-top-width:5px;border-right-width:5px;border-left-width:5px}.btn-mini .caret,.btn-small .caret{margin-top:8px}.dropup .btn-large .caret{border-bottom-width:5px}.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#fff;border-bottom-color:#fff}.btn-group-vertical{display:inline-block;*display:inline;*zoom:1}.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.btn-group-vertical>.btn+.btn{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255,255,255,0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.alert,.alert h4{color:#c09853}.alert h4{margin:0}.alert .close{position:relative;top:-2px;right:-21px;line-height:20px}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success h4{color:#468847}.alert-danger,.alert-error{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger h4,.alert-error h4{color:#b94a48}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info h4{color:#3a87ad}.alert-block{padding-top:14px;padding-bottom:14px}.alert-block>p,.alert-block>ul{margin-bottom:0}.alert-block p+p{margin-top:5px}.nav{margin-bottom:20px;margin-left:0;list-style:none}.nav>li>a{display:block}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li>a>img{max-width:none}.nav>.pull-right{float:right}.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.5);text-transform:uppercase}.nav li+.nav-header{margin-top:9px}.nav-list{padding-right:15px;padding-left:15px;margin-bottom:0}.nav-list>li>a,.nav-list .nav-header{margin-right:-15px;margin-left:-15px;text-shadow:0 1px 0 rgba(255,255,255,0.5)}.nav-list>li>a{padding:3px 15px}.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.2);background-color:#08c}.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px}.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #fff}.nav-tabs,.nav-pills{*zoom:1}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;line-height:0;content:""}.nav-tabs:after,.nav-pills:after{clear:both}.nav-tabs>li,.nav-pills>li{float:left}.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{margin-bottom:-1px}.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eee #eee #ddd}.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#fff;background-color:#08c}.nav-stacked>li{float:none}.nav-stacked>li>a{margin-right:0}.nav-tabs.nav-stacked{border-bottom:0}.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-topleft:4px}.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomright:4px;-moz-border-radius-bottomleft:4px}.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{z-index:2;border-color:#ddd}.nav-pills.nav-stacked>li>a{margin-bottom:3px}.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px}.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.nav .dropdown-toggle .caret{margin-top:6px;border-top-color:#08c;border-bottom-color:#08c}.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580}.nav-tabs .dropdown-toggle .caret{margin-top:8px}.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#fff;background-color:#999;border-color:#999}.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#fff;border-bottom-color:#fff;opacity:1;filter:alpha(opacity=100)}.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999}.tabbable{*zoom:1}.tabbable:before,.tabbable:after{display:table;line-height:0;content:""}.tabbable:after{clear:both}.tab-content{overflow:auto}.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0}.tab-content>.tab-pane,.pill-content>.pill-pane{display:none}.tab-content>.active,.pill-content>.active{display:block}.tabs-below>.nav-tabs{border-top:1px solid #ddd}.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0}.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-top-color:#ddd;border-bottom-color:transparent}.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd}.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none}.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px}.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd}.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px}.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eee #ddd #eee #eee}.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#fff}.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd}.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0}.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eee #eee #eee #ddd}.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#fff}.nav>.disabled>a{color:#999}.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;cursor:default;background-color:transparent}.navbar{*position:relative;*z-index:2;margin-bottom:20px;overflow:visible}.navbar-inner{min-height:40px;padding-right:20px;padding-left:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top,#fff,#f2f2f2);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fff),to(#f2f2f2));background-image:-webkit-linear-gradient(top,#fff,#f2f2f2);background-image:-o-linear-gradient(top,#fff,#f2f2f2);background-image:linear-gradient(to bottom,#fff,#f2f2f2);background-repeat:repeat-x;border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff2f2f2',GradientType=0);*zoom:1;-webkit-box-shadow:0 1px 4px rgba(0,0,0,0.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,0.065);box-shadow:0 1px 4px rgba(0,0,0,0.065)}.navbar-inner:before,.navbar-inner:after{display:table;line-height:0;content:""}.navbar-inner:after{clear:both}.navbar .container{width:auto}.nav-collapse.collapse{height:auto;overflow:visible}.navbar .brand{display:block;float:left;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777;text-shadow:0 1px 0 #fff}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none}.navbar-text{margin-bottom:0;line-height:40px;color:#777}.navbar-link{color:#777}.navbar-link:hover,.navbar-link:focus{color:#333}.navbar .divider-vertical{height:40px;margin:0 9px;border-right:1px solid #fff;border-left:1px solid #f2f2f2}.navbar .btn,.navbar .btn-group{margin-top:5px}.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0}.navbar-form{margin-bottom:0;*zoom:1}.navbar-form:before,.navbar-form:after{display:table;line-height:0;content:""}.navbar-form:after{clear:both}.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px}.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0}.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px}.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0}.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0}.navbar-search .search-query{padding:4px 14px;margin-bottom:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.navbar-static-top{position:static;margin-bottom:0}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px}.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0}.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-right:0;padding-left:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px}.navbar-fixed-top{top:0}.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar-fixed-bottom{bottom:0}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,0.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,0.1);box-shadow:0 -1px 10px rgba(0,0,0,0.1)}.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0}.navbar .nav.pull-right{float:right;margin-right:0}.navbar .nav>li{float:left}.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777;text-decoration:none;text-shadow:0 1px 0 #fff}.navbar .nav .dropdown-toggle .caret{margin-top:8px}.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{color:#333;text-decoration:none;background-color:transparent}.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);-moz-box-shadow:inset 0 3px 8px rgba(0,0,0,0.125);box-shadow:inset 0 3px 8px rgba(0,0,0,0.125)}.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-right:5px;margin-left:5px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#ededed;*background-color:#e5e5e5;background-image:-moz-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f2f2f2),to(#e5e5e5));background-image:-webkit-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:-o-linear-gradient(top,#f2f2f2,#e5e5e5);background-image:linear-gradient(to bottom,#f2f2f2,#e5e5e5);background-repeat:repeat-x;border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2',endColorstr='#ffe5e5e5',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.075)}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#fff;background-color:#e5e5e5;*background-color:#d9d9d9}.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#ccc \9}.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0,0,0,0.25);-moz-box-shadow:0 1px 0 rgba(0,0,0,0.25);box-shadow:0 1px 0 rgba(0,0,0,0.25)}.btn-navbar .icon-bar+.icon-bar{margin-top:3px}.navbar .nav>li>.dropdown-menu:before{position:absolute;top:-7px;left:9px;display:inline-block;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,0.2);content:''}.navbar .nav>li>.dropdown-menu:after{position:absolute;top:-6px;left:10px;display:inline-block;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent;content:''}.navbar-fixed-bottom .nav>li>.dropdown-menu:before{top:auto;bottom:-7px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.navbar-fixed-bottom .nav>li>.dropdown-menu:after{top:auto;bottom:-6px;border-top:6px solid #fff;border-bottom:0}.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333;border-bottom-color:#333}.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{color:#555;background-color:#e5e5e5}.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777;border-bottom-color:#777}.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555;border-bottom-color:#555}.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{right:12px;left:auto}.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{right:13px;left:auto}.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{right:100%;left:auto;margin-right:-1px;margin-left:0;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top,#222,#111);background-image:-webkit-gradient(linear,0 0,0 100%,from(#222),to(#111));background-image:-webkit-linear-gradient(top,#222,#111);background-image:-o-linear-gradient(top,#222,#111);background-image:linear-gradient(to bottom,#222,#111);background-repeat:repeat-x;border-color:#252525;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0)}.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999;text-shadow:0 -1px 0 rgba(0,0,0,0.25)}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#fff}.navbar-inverse .brand{color:#999}.navbar-inverse .navbar-text{color:#999}.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{color:#fff;background-color:transparent}.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#fff;background-color:#111}.navbar-inverse .navbar-link{color:#999}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#fff}.navbar-inverse .divider-vertical{border-right-color:#222;border-left-color:#111}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{color:#fff;background-color:#111}.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999;border-bottom-color:#999}.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff}.navbar-inverse .navbar-search .search-query{color:#fff;background-color:#515151;border-color:#111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1),0 1px 0 rgba(255,255,255,0.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#ccc}.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333;text-shadow:0 1px 0 #fff;background-color:#fff;border:0;outline:0;-webkit-box-shadow:0 0 3px rgba(0,0,0,0.15);-moz-box-shadow:0 0 3px rgba(0,0,0,0.15);box-shadow:0 0 3px rgba(0,0,0,0.15)}.navbar-inverse .btn-navbar{color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e0e0e;*background-color:#040404;background-image:-moz-linear-gradient(top,#151515,#040404);background-image:-webkit-gradient(linear,0 0,0 100%,from(#151515),to(#040404));background-image:-webkit-linear-gradient(top,#151515,#040404);background-image:-o-linear-gradient(top,#151515,#040404);background-image:linear-gradient(to bottom,#151515,#040404);background-repeat:repeat-x;border-color:#040404 #040404 #000;border-color:rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515',endColorstr='#ff040404',GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#fff;background-color:#040404;*background-color:#000}.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000 \9}.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.breadcrumb>li{display:inline-block;*display:inline;text-shadow:0 1px 0 #fff;*zoom:1}.breadcrumb>li>.divider{padding:0 5px;color:#ccc}.breadcrumb>.active{color:#999}.pagination{margin:20px 0}.pagination ul{display:inline-block;*display:inline;margin-bottom:0;margin-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1;-webkit-box-shadow:0 1px 2px rgba(0,0,0,0.05);-moz-box-shadow:0 1px 2px rgba(0,0,0,0.05);box-shadow:0 1px 2px rgba(0,0,0,0.05)}.pagination ul>li{display:inline}.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#fff;border:1px solid #ddd;border-left-width:0}.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5}.pagination ul>.active>a,.pagination ul>.active>span{color:#999;cursor:default}.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999;cursor:default;background-color:transparent}.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-bottomleft:4px;-moz-border-radius-topleft:4px}.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-topright:4px;-moz-border-radius-bottomright:4px}.pagination-centered{text-align:center}.pagination-right{text-align:right}.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px}.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-bottom-left-radius:6px;border-bottom-left-radius:6px;-webkit-border-top-left-radius:6px;border-top-left-radius:6px;-moz-border-radius-bottomleft:6px;-moz-border-radius-topleft:6px}.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;border-bottom-right-radius:6px;-moz-border-radius-topright:6px;-moz-border-radius-bottomright:6px}.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-bottom-left-radius:3px;border-bottom-left-radius:3px;-webkit-border-top-left-radius:3px;border-top-left-radius:3px;-moz-border-radius-bottomleft:3px;-moz-border-radius-topleft:3px}.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;border-bottom-right-radius:3px;-moz-border-radius-topright:3px;-moz-border-radius-bottomright:3px}.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px}.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px}.pager{margin:20px 0;text-align:center;list-style:none;*zoom:1}.pager:before,.pager:after{display:table;line-height:0;content:""}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:default;background-color:#fff}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop,.modal-backdrop.fade.in{opacity:.8;filter:alpha(opacity=80)}.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;outline:0;-webkit-box-shadow:0 3px 7px rgba(0,0,0,0.3);-moz-box-shadow:0 3px 7px rgba(0,0,0,0.3);box-shadow:0 3px 7px rgba(0,0,0,0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box}.modal.fade{top:-25%;-webkit-transition:opacity .3s linear,top .3s ease-out;-moz-transition:opacity .3s linear,top .3s ease-out;-o-transition:opacity .3s linear,top .3s ease-out;transition:opacity .3s linear,top .3s ease-out}.modal.fade.in{top:10%}.modal-header{padding:9px 15px;border-bottom:1px solid #eee}.modal-header .close{margin-top:2px}.modal-header h3{margin:0;line-height:30px}.modal-body{position:relative;max-height:400px;padding:15px;overflow-y:auto}.modal-form{margin-bottom:0}.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;*zoom:1;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.modal-footer:before,.modal-footer:after{display:table;line-height:0;content:""}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}.tooltip{position:absolute;z-index:1030;display:block;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.8;filter:alpha(opacity=80)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:8px;color:#fff;text-align:center;text-decoration:none;background-color:#000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:#000;border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:#000;border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:#000;border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:#000;border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);-moz-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0}.popover-title:empty{display:none}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0}.thumbnails{margin-left:-20px;list-style:none;*zoom:1}.thumbnails:before,.thumbnails:after{display:table;line-height:0;content:""}.thumbnails:after{clear:both}.row-fluid .thumbnails{margin-left:0}.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px}.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,0.055);-moz-box-shadow:0 1px 3px rgba(0,0,0,0.055);box-shadow:0 1px 3px rgba(0,0,0,0.055);-webkit-transition:all .2s ease-in-out;-moz-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}a.thumbnail:hover,a.thumbnail:focus{border-color:#08c;-webkit-box-shadow:0 1px 4px rgba(0,105,214,0.25);-moz-box-shadow:0 1px 4px rgba(0,105,214,0.25);box-shadow:0 1px 4px rgba(0,105,214,0.25)}.thumbnail>img{display:block;max-width:100%;margin-right:auto;margin-left:auto}.thumbnail .caption{padding:9px;color:#555}.media,.media-body{overflow:hidden;*overflow:visible;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{margin-left:0;list-style:none}.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,0.25);white-space:nowrap;vertical-align:baseline;background-color:#999}.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.badge{padding-right:9px;padding-left:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px}.label:empty,.badge:empty{display:none}a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}.label-important,.badge-important{background-color:#b94a48}.label-important[href],.badge-important[href]{background-color:#953b39}.label-warning,.badge-warning{background-color:#f89406}.label-warning[href],.badge-warning[href]{background-color:#c67605}.label-success,.badge-success{background-color:#468847}.label-success[href],.badge-success[href]{background-color:#356635}.label-info,.badge-info{background-color:#3a87ad}.label-info[href],.badge-info[href]{background-color:#2d6987}.label-inverse,.badge-inverse{background-color:#333}.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a}.btn .label,.btn .badge{position:relative;top:-1px}.btn-mini .label,.btn-mini .badge{top:0}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@-o-keyframes progress-bar-stripes{from{background-position:0 0}to{background-position:40px 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f7f7f7;background-image:-moz-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#f5f5f5),to(#f9f9f9));background-image:-webkit-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:-o-linear-gradient(top,#f5f5f5,#f9f9f9);background-image:linear-gradient(to bottom,#f5f5f5,#f9f9f9);background-repeat:repeat-x;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5',endColorstr='#fff9f9f9',GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress .bar{float:left;width:0;height:100%;font-size:12px;color:#fff;text-align:center;text-shadow:0 -1px 0 rgba(0,0,0,0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top,#149bdf,#0480be);background-image:-webkit-gradient(linear,0 0,0 100%,from(#149bdf),to(#0480be));background-image:-webkit-linear-gradient(top,#149bdf,#0480be);background-image:-o-linear-gradient(top,#149bdf,#0480be);background-image:linear-gradient(to bottom,#149bdf,#0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf',endColorstr='#ff0480be',GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width .6s ease;-moz-transition:width .6s ease;-o-transition:width .6s ease;transition:width .6s ease}.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 1px 0 0 rgba(0,0,0,0.15),inset 0 -1px 0 rgba(0,0,0,0.15)}.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px}.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top,#ee5f5b,#c43c35);background-image:-webkit-gradient(linear,0 0,0 100%,from(#ee5f5b),to(#c43c35));background-image:-webkit-linear-gradient(top,#ee5f5b,#c43c35);background-image:-o-linear-gradient(top,#ee5f5b,#c43c35);background-image:linear-gradient(to bottom,#ee5f5b,#c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b',endColorstr='#ffc43c35',GradientType=0)}.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top,#62c462,#57a957);background-image:-webkit-gradient(linear,0 0,0 100%,from(#62c462),to(#57a957));background-image:-webkit-linear-gradient(top,#62c462,#57a957);background-image:-o-linear-gradient(top,#62c462,#57a957);background-image:linear-gradient(to bottom,#62c462,#57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462',endColorstr='#ff57a957',GradientType=0)}.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top,#5bc0de,#339bb9);background-image:-webkit-gradient(linear,0 0,0 100%,from(#5bc0de),to(#339bb9));background-image:-webkit-linear-gradient(top,#5bc0de,#339bb9);background-image:-o-linear-gradient(top,#5bc0de,#339bb9);background-image:linear-gradient(to bottom,#5bc0de,#339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de',endColorstr='#ff339bb9',GradientType=0)}.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top,#fbb450,#f89406);background-image:-webkit-gradient(linear,0 0,0 100%,from(#fbb450),to(#f89406));background-image:-webkit-linear-gradient(top,#fbb450,#f89406);background-image:-o-linear-gradient(top,#fbb450,#f89406);background-image:linear-gradient(to bottom,#fbb450,#f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450',endColorstr='#fff89406',GradientType=0)}.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear,0 100%,100% 0,color-stop(0.25,rgba(255,255,255,0.15)),color-stop(0.25,transparent),color-stop(0.5,transparent),color-stop(0.5,rgba(255,255,255,0.15)),color-stop(0.75,rgba(255,255,255,0.15)),color-stop(0.75,transparent),to(transparent));background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-moz-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.accordion{margin-bottom:20px}.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px}.accordion-heading{border-bottom:0}.accordion-heading .accordion-toggle{display:block;padding:8px 15px}.accordion-toggle{cursor:pointer}.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5}.carousel{position:relative;margin-bottom:20px;line-height:1}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;-moz-transition:.6s ease-in-out left;-o-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#fff;text-align:center;background:#222;border:3px solid #fff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:.5;filter:alpha(opacity=50)}.carousel-control.right{right:15px;left:auto}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;opacity:.9;filter:alpha(opacity=90)}.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255,255,255,0.25);border-radius:5px}.carousel-indicators .active{background-color:#fff}.carousel-caption{position:absolute;right:0;bottom:0;left:0;padding:15px;background:#333;background:rgba(0,0,0,0.75)}.carousel-caption h4,.carousel-caption p{line-height:20px;color:#fff}.carousel-caption h4{margin:0 0 5px}.carousel-caption p{margin-bottom:0}.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;color:inherit}.hero-unit li{line-height:30px}.pull-right{float:right}.pull-left{float:left}.hide{display:none}.show{display:block}.invisible{visibility:hidden}.affix{position:fixed} diff --git a/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png b/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png new file mode 100644 index 00000000..3bf6484a Binary files /dev/null and b/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings-white.png differ diff --git a/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings.png b/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings.png new file mode 100644 index 00000000..a9969993 Binary files /dev/null and b/docs/_static/bootstrap-2.3.2/img/glyphicons-halflings.png differ diff --git a/docs/_static/bootstrap-2.3.2/js/bootstrap.js b/docs/_static/bootstrap-2.3.2/js/bootstrap.js new file mode 100644 index 00000000..638bb187 --- /dev/null +++ b/docs/_static/bootstrap-2.3.2/js/bootstrap.js @@ -0,0 +1,2287 @@ +/* =================================================== + * bootstrap-transition.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#transitions + * =================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CSS TRANSITION SUPPORT (http://www.modernizr.com/) + * ======================================================= */ + + $(function () { + + $.support.transition = (function () { + + var transitionEnd = (function () { + + var el = document.createElement('bootstrap') + , transEndEventNames = { + 'WebkitTransition' : 'webkitTransitionEnd' + , 'MozTransition' : 'transitionend' + , 'OTransition' : 'oTransitionEnd otransitionend' + , 'transition' : 'transitionend' + } + , name + + for (name in transEndEventNames){ + if (el.style[name] !== undefined) { + return transEndEventNames[name] + } + } + + }()) + + return transitionEnd && { + end: transitionEnd + } + + })() + + }) + +}(window.$jqTheme || window.jQuery); +/* ========================================================== + * bootstrap-alert.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#alerts + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* ALERT CLASS DEFINITION + * ====================== */ + + var dismiss = '[data-dismiss="alert"]' + , Alert = function (el) { + $(el).on('click', dismiss, this.close) + } + + Alert.prototype.close = function (e) { + var $this = $(this) + , selector = $this.attr('data-target') + , $parent + + if (!selector) { + selector = $this.attr('href') + selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7 + } + + $parent = $(selector) + + e && e.preventDefault() + + $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent()) + + $parent.trigger(e = $.Event('close')) + + if (e.isDefaultPrevented()) return + + $parent.removeClass('in') + + function removeElement() { + $parent + .trigger('closed') + .remove() + } + + $.support.transition && $parent.hasClass('fade') ? + $parent.on($.support.transition.end, removeElement) : + removeElement() + } + + + /* ALERT PLUGIN DEFINITION + * ======================= */ + + var old = $.fn.alert + + $.fn.alert = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('alert') + if (!data) $this.data('alert', (data = new Alert(this))) + if (typeof option == 'string') data[option].call($this) + }) + } + + $.fn.alert.Constructor = Alert + + + /* ALERT NO CONFLICT + * ================= */ + + $.fn.alert.noConflict = function () { + $.fn.alert = old + return this + } + + + /* ALERT DATA-API + * ============== */ + + $(document).on('click.alert.data-api', dismiss, Alert.prototype.close) + +}(window.$jqTheme || window.jQuery); +/* ============================================================ + * bootstrap-button.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#buttons + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* BUTTON PUBLIC CLASS DEFINITION + * ============================== */ + + var Button = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.button.defaults, options) + } + + Button.prototype.setState = function (state) { + var d = 'disabled' + , $el = this.$element + , data = $el.data() + , val = $el.is('input') ? 'val' : 'html' + + state = state + 'Text' + data.resetText || $el.data('resetText', $el[val]()) + + $el[val](data[state] || this.options[state]) + + // push to event loop to allow forms to submit + setTimeout(function () { + state == 'loadingText' ? + $el.addClass(d).attr(d, d) : + $el.removeClass(d).removeAttr(d) + }, 0) + } + + Button.prototype.toggle = function () { + var $parent = this.$element.closest('[data-toggle="buttons-radio"]') + + $parent && $parent + .find('.active') + .removeClass('active') + + this.$element.toggleClass('active') + } + + + /* BUTTON PLUGIN DEFINITION + * ======================== */ + + var old = $.fn.button + + $.fn.button = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('button') + , options = typeof option == 'object' && option + if (!data) $this.data('button', (data = new Button(this, options))) + if (option == 'toggle') data.toggle() + else if (option) data.setState(option) + }) + } + + $.fn.button.defaults = { + loadingText: 'loading...' + } + + $.fn.button.Constructor = Button + + + /* BUTTON NO CONFLICT + * ================== */ + + $.fn.button.noConflict = function () { + $.fn.button = old + return this + } + + + /* BUTTON DATA-API + * =============== */ + + $(document).on('click.button.data-api', '[data-toggle^=button]', function (e) { + var $btn = $(e.target) + if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn') + $btn.button('toggle') + }) + +}(window.$jqTheme || window.jQuery); +/* ========================================================== + * bootstrap-carousel.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#carousel + * ========================================================== + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ========================================================== */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* CAROUSEL CLASS DEFINITION + * ========================= */ + + var Carousel = function (element, options) { + this.$element = $(element) + this.$indicators = this.$element.find('.carousel-indicators') + this.options = options + this.options.pause == 'hover' && this.$element + .on('mouseenter', $.proxy(this.pause, this)) + .on('mouseleave', $.proxy(this.cycle, this)) + } + + Carousel.prototype = { + + cycle: function (e) { + if (!e) this.paused = false + if (this.interval) clearInterval(this.interval); + this.options.interval + && !this.paused + && (this.interval = setInterval($.proxy(this.next, this), this.options.interval)) + return this + } + + , getActiveIndex: function () { + this.$active = this.$element.find('.item.active') + this.$items = this.$active.parent().children() + return this.$items.index(this.$active) + } + + , to: function (pos) { + var activeIndex = this.getActiveIndex() + , that = this + + if (pos > (this.$items.length - 1) || pos < 0) return + + if (this.sliding) { + return this.$element.one('slid', function () { + that.to(pos) + }) + } + + if (activeIndex == pos) { + return this.pause().cycle() + } + + return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos])) + } + + , pause: function (e) { + if (!e) this.paused = true + if (this.$element.find('.next, .prev').length && $.support.transition.end) { + this.$element.trigger($.support.transition.end) + this.cycle(true) + } + clearInterval(this.interval) + this.interval = null + return this + } + + , next: function () { + if (this.sliding) return + return this.slide('next') + } + + , prev: function () { + if (this.sliding) return + return this.slide('prev') + } + + , slide: function (type, next) { + var $active = this.$element.find('.item.active') + , $next = next || $active[type]() + , isCycling = this.interval + , direction = type == 'next' ? 'left' : 'right' + , fallback = type == 'next' ? 'first' : 'last' + , that = this + , e + + this.sliding = true + + isCycling && this.pause() + + $next = $next.length ? $next : this.$element.find('.item')[fallback]() + + e = $.Event('slide', { + relatedTarget: $next[0] + , direction: direction + }) + + if ($next.hasClass('active')) return + + if (this.$indicators.length) { + this.$indicators.find('.active').removeClass('active') + this.$element.one('slid', function () { + var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()]) + $nextIndicator && $nextIndicator.addClass('active') + }) + } + + if ($.support.transition && this.$element.hasClass('slide')) { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $next.addClass(type) + $next[0].offsetWidth // force reflow + $active.addClass(direction) + $next.addClass(direction) + this.$element.one($.support.transition.end, function () { + $next.removeClass([type, direction].join(' ')).addClass('active') + $active.removeClass(['active', direction].join(' ')) + that.sliding = false + setTimeout(function () { that.$element.trigger('slid') }, 0) + }) + } else { + this.$element.trigger(e) + if (e.isDefaultPrevented()) return + $active.removeClass('active') + $next.addClass('active') + this.sliding = false + this.$element.trigger('slid') + } + + isCycling && this.cycle() + + return this + } + + } + + + /* CAROUSEL PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.carousel + + $.fn.carousel = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('carousel') + , options = $.extend({}, $.fn.carousel.defaults, typeof option == 'object' && option) + , action = typeof option == 'string' ? option : options.slide + if (!data) $this.data('carousel', (data = new Carousel(this, options))) + if (typeof option == 'number') data.to(option) + else if (action) data[action]() + else if (options.interval) data.pause().cycle() + }) + } + + $.fn.carousel.defaults = { + interval: 5000 + , pause: 'hover' + } + + $.fn.carousel.Constructor = Carousel + + + /* CAROUSEL NO CONFLICT + * ==================== */ + + $.fn.carousel.noConflict = function () { + $.fn.carousel = old + return this + } + + /* CAROUSEL DATA-API + * ================= */ + + $(document).on('click.carousel.data-api', '[data-slide], [data-slide-to]', function (e) { + var $this = $(this), href + , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7 + , options = $.extend({}, $target.data(), $this.data()) + , slideIndex + + $target.carousel(options) + + if (slideIndex = $this.attr('data-slide-to')) { + $target.data('carousel').pause().to(slideIndex).cycle() + } + + e.preventDefault() + }) + +}(window.$jqTheme || window.jQuery); +/* ============================================================= + * bootstrap-collapse.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#collapse + * ============================================================= + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* COLLAPSE PUBLIC CLASS DEFINITION + * ================================ */ + + var Collapse = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, $.fn.collapse.defaults, options) + + if (this.options.parent) { + this.$parent = $(this.options.parent) + } + + this.options.toggle && this.toggle() + } + + Collapse.prototype = { + + constructor: Collapse + + , dimension: function () { + var hasWidth = this.$element.hasClass('width') + return hasWidth ? 'width' : 'height' + } + + , show: function () { + var dimension + , scroll + , actives + , hasData + + if (this.transitioning || this.$element.hasClass('in')) return + + dimension = this.dimension() + scroll = $.camelCase(['scroll', dimension].join('-')) + actives = this.$parent && this.$parent.find('> .accordion-group > .in') + + if (actives && actives.length) { + hasData = actives.data('collapse') + if (hasData && hasData.transitioning) return + actives.collapse('hide') + hasData || actives.data('collapse', null) + } + + this.$element[dimension](0) + this.transition('addClass', $.Event('show'), 'shown') + $.support.transition && this.$element[dimension](this.$element[0][scroll]) + } + + , hide: function () { + var dimension + if (this.transitioning || !this.$element.hasClass('in')) return + dimension = this.dimension() + this.reset(this.$element[dimension]()) + this.transition('removeClass', $.Event('hide'), 'hidden') + this.$element[dimension](0) + } + + , reset: function (size) { + var dimension = this.dimension() + + this.$element + .removeClass('collapse') + [dimension](size || 'auto') + [0].offsetWidth + + this.$element[size !== null ? 'addClass' : 'removeClass']('collapse') + + return this + } + + , transition: function (method, startEvent, completeEvent) { + var that = this + , complete = function () { + if (startEvent.type == 'show') that.reset() + that.transitioning = 0 + that.$element.trigger(completeEvent) + } + + this.$element.trigger(startEvent) + + if (startEvent.isDefaultPrevented()) return + + this.transitioning = 1 + + this.$element[method]('in') + + $.support.transition && this.$element.hasClass('collapse') ? + this.$element.one($.support.transition.end, complete) : + complete() + } + + , toggle: function () { + this[this.$element.hasClass('in') ? 'hide' : 'show']() + } + + } + + + /* COLLAPSE PLUGIN DEFINITION + * ========================== */ + + var old = $.fn.collapse + + $.fn.collapse = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('collapse') + , options = $.extend({}, $.fn.collapse.defaults, $this.data(), typeof option == 'object' && option) + if (!data) $this.data('collapse', (data = new Collapse(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.collapse.defaults = { + toggle: true + } + + $.fn.collapse.Constructor = Collapse + + + /* COLLAPSE NO CONFLICT + * ==================== */ + + $.fn.collapse.noConflict = function () { + $.fn.collapse = old + return this + } + + + /* COLLAPSE DATA-API + * ================= */ + + $(document).on('click.collapse.data-api', '[data-toggle=collapse]', function (e) { + var $this = $(this), href + , target = $this.attr('data-target') + || e.preventDefault() + || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7 + , option = $(target).data('collapse') ? 'toggle' : $this.data() + $this[$(target).hasClass('in') ? 'addClass' : 'removeClass']('collapsed') + $(target).collapse(option) + }) + +}(window.$jqTheme || window.jQuery); +/* ============================================================ + * bootstrap-dropdown.js v2.3.2 + * http://twitter.github.com/bootstrap/javascript.html#dropdowns + * ============================================================ + * Copyright 2012 Twitter, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============================================================ */ + + +!function ($) { + + "use strict"; // jshint ;_; + + + /* DROPDOWN CLASS DEFINITION + * ========================= */ + + var toggle = '[data-toggle=dropdown]' + , Dropdown = function (element) { + var $el = $(element).on('click.dropdown.data-api', this.toggle) + $('html').on('click.dropdown.data-api', function () { + $el.parent().removeClass('open') + }) + } + + Dropdown.prototype = { + + constructor: Dropdown + + , toggle: function (e) { + var $this = $(this) + , $parent + , isActive + + if ($this.is('.disabled, :disabled')) return + + $parent = getParent($this) + + isActive = $parent.hasClass('open') + + clearMenus() + + if (!isActive) { + if ('ontouchstart' in document.documentElement) { + // if mobile we we use a backdrop because click events don't delegate + $('