diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..0f35b37 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ + +# .travis.yml + +script: bundle exec rake travis + +env: + - secure: "ldxWJXz2Z0hhjYETZ7qW0R3IBvBHCE5ZNLS4CYawEQKCGBPneePA8o5/evw8K8Ra3yQI3Ba/XmRZlPQ3aHxW+GReb7yb/HDhe+9obUKikBXvDXErUKQm/2G0PrhXm518uBxaChfQBj2psq9FjnbrHX6ZcVU7L2JhoQfedOOFt9Q=" + +branches: + only: + - master diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..6a6c997 --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source "https://rubygems.org" + +gem 'rake', '~> 10.4.2' +gem 'jekyll', '~> 2.5.2' diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..3707a0d --- /dev/null +++ b/Rakefile @@ -0,0 +1,49 @@ +require 'fileutils' +require 'rake' +require 'tmpdir' + +destination = './docs/_site/' + +desc 'Builds the website using Jekyll' +task :build do + puts 'Rendering markdown to HTML with Jekyll' + sh "cd docs && jekyll build" + puts 'Rendering finished- results are in _site' +end + +# From Evan Osenko @ https://evansosenko.com/posts/automatic-publishing-github-pages-travis-ci/ +desc 'Generate deck from Travis CI and publish to GitHub Pages.' +task :travis do + # if this is a pull request, do a simple build of the site and stop + if ENV['TRAVIS_PULL_REQUEST'].to_s.to_i > 0 + puts 'Pull request detected. Executing build only.' + sh 'bundle exec rake build' + next + end + + repo = %x(git config remote.origin.url).gsub(/^git:/, 'https:').strip + deploy_url = repo.gsub %r{https://}, "https://#{ENV['GH_TOKEN']}@" + deploy_branch = repo.match(/github\.io\.git$/) ? 'master' : 'gh-pages' + rev = %x(git rev-parse HEAD).strip + + Dir.mktmpdir do |dir| + dir = File.join dir, 'site' + sh 'bundle exec rake build' + fail "Build failed." unless Dir.exists? destination + sh "git clone --branch #{deploy_branch} #{repo} #{dir}" + sh %Q(rsync -rt --del --exclude=".git" --exclude=".nojekyll" #{destination} #{dir}) + Dir.chdir dir do + # setup credentials so Travis CI can push to GitHub + verbose false do + sh "git config user.name '#{ENV['GIT_NAME']}'" + sh "git config user.email '#{ENV['GIT_EMAIL']}'" + end + + sh 'git add --all' + sh "git commit -m 'Built from #{rev}'." + verbose false do + sh "git push -q #{deploy_url} #{deploy_branch}" + end + end + end +end diff --git a/docs/Gemfile b/docs/Gemfile new file mode 100644 index 0000000..053c27d --- /dev/null +++ b/docs/Gemfile @@ -0,0 +1,2 @@ +source 'https://rubygems.org' +gem 'github-pages' diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock new file mode 100644 index 0000000..8b11eb9 --- /dev/null +++ b/docs/Gemfile.lock @@ -0,0 +1,96 @@ +GEM + remote: https://rubygems.org/ + specs: + RedCloth (4.2.9) + activesupport (4.1.1) + i18n (~> 0.6, >= 0.6.9) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.1) + tzinfo (~> 1.1) + blankslate (2.1.2.4) + classifier (1.3.4) + fast-stemmer (>= 1.0.0) + colorator (0.1) + commander (4.1.6) + highline (~> 1.6.11) + fast-stemmer (1.0.2) + ffi (1.9.3) + gemoji (1.5.0) + github-pages (19) + RedCloth (= 4.2.9) + jekyll (= 1.5.1) + jekyll-mentions (= 0.0.6) + jekyll-redirect-from (= 0.3.1) + jekyll-sitemap (= 0.3.0) + jemoji (= 0.1.0) + kramdown (= 1.3.1) + liquid (= 2.5.5) + maruku (= 0.7.0) + rdiscount (= 2.1.7) + redcarpet (= 2.3.0) + highline (1.6.21) + html-pipeline (1.5.0) + activesupport (>= 2) + nokogiri (~> 1.4) + i18n (0.6.9) + jekyll (1.5.1) + classifier (~> 1.3) + colorator (~> 0.1) + commander (~> 4.1.3) + liquid (~> 2.5.5) + listen (~> 1.3) + maruku (= 0.7.0) + pygments.rb (~> 0.5.0) + redcarpet (~> 2.3.0) + safe_yaml (~> 1.0) + toml (~> 0.1.0) + jekyll-mentions (0.0.6) + html-pipeline (~> 1.5.0) + jekyll (~> 1.4) + jekyll-redirect-from (0.3.1) + jekyll (~> 1.4) + jekyll-sitemap (0.3.0) + jekyll (~> 1.4) + jemoji (0.1.0) + gemoji (~> 1.5.0) + html-pipeline (~> 1.5.0) + jekyll (~> 1.4) + json (1.8.1) + kramdown (1.3.1) + liquid (2.5.5) + listen (1.3.1) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + rb-kqueue (>= 0.2) + maruku (0.7.0) + mini_portile (0.6.0) + minitest (5.3.4) + nokogiri (1.6.2.1) + mini_portile (= 0.6.0) + parslet (1.5.0) + blankslate (~> 2.0) + posix-spawn (0.3.8) + pygments.rb (0.5.4) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.1.0) + rb-fsevent (0.9.4) + rb-inotify (0.9.4) + ffi (>= 0.5.0) + rb-kqueue (0.2.3) + ffi (>= 0.5.0) + rdiscount (2.1.7) + redcarpet (2.3.0) + safe_yaml (1.0.3) + thread_safe (0.3.4) + toml (0.1.1) + parslet (~> 1.5.0) + tzinfo (1.2.1) + thread_safe (~> 0.1) + yajl-ruby (1.1.0) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages diff --git a/docs/_config.yml b/docs/_config.yml new file mode 100644 index 0000000..48c3c70 --- /dev/null +++ b/docs/_config.yml @@ -0,0 +1,48 @@ +plugins: ./_plugins +layouts: ./_layouts +include: ['.htaccess'] +exclude: [] +keep_files: ['.git','.svn'] +gems: [] +timezone: nil +encoding: utf-8 + +future: true +show_drafts: nil +limit_posts: 0 +highlighter: pygments + +relative_permalinks: true + +permalink: date +paginate_path: 'page:num' +paginate: nil + +markdown: kramdown +markdown_ext: markdown,mkdown,mkdn,mkd,md +textile_ext: textile + +excerpt_separator: "\n\n" + +defaults: + - + scope: + path: "" + values: + layout: "page" + +kramdown: + auto_ids: true + footnote_nr: 1 + entity_output: as_char + toc_levels: 1..6 + smart_quotes: lsquo,rsquo,ldquo,rdquo + use_coderay: false + + coderay: + coderay_wrap: div + coderay_line_numbers: inline + coderay_line_numbers_start: 1 + coderay_tab_width: 4 + coderay_bold_every: 10 + coderay_css: style diff --git a/docs/_layouts/page.html b/docs/_layouts/page.html new file mode 100644 index 0000000..a486e6b --- /dev/null +++ b/docs/_layouts/page.html @@ -0,0 +1,49 @@ + + + + + + + + + + + + PCP Quality Assessment Protocol + + + + +
+ + +
+ + +

PCP Quality Assessment Protocol


+ +
+ +
+
+ {{ content }} +
+
+ + + + +
+ + diff --git a/docs/example_FD.png b/docs/example_FD.png new file mode 100644 index 0000000..820a226 Binary files /dev/null and b/docs/example_FD.png differ diff --git a/docs/example_mean_EPI.png b/docs/example_mean_EPI.png new file mode 100644 index 0000000..8df9f91 Binary files /dev/null and b/docs/example_mean_EPI.png differ diff --git a/docs/example_tSNR.png b/docs/example_tSNR.png new file mode 100644 index 0000000..296433f Binary files /dev/null and b/docs/example_tSNR.png differ diff --git a/docs/functional_spatial_violins.png b/docs/functional_spatial_violins.png new file mode 100644 index 0000000..5bba6ef Binary files /dev/null and b/docs/functional_spatial_violins.png differ diff --git a/docs/images/bg_hr.png b/docs/images/bg_hr.png new file mode 100644 index 0000000..7973bd6 Binary files /dev/null and b/docs/images/bg_hr.png differ diff --git a/docs/images/blacktocat.png b/docs/images/blacktocat.png new file mode 100644 index 0000000..6e264fe Binary files /dev/null and b/docs/images/blacktocat.png differ diff --git a/docs/images/icon_download.png b/docs/images/icon_download.png new file mode 100644 index 0000000..a2a287f Binary files /dev/null and b/docs/images/icon_download.png differ diff --git a/docs/images/sprite_download.png b/docs/images/sprite_download.png new file mode 100644 index 0000000..f2babd5 Binary files /dev/null and b/docs/images/sprite_download.png differ diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..345e7bf --- /dev/null +++ b/docs/index.md @@ -0,0 +1,351 @@ +--- +layout: page +title: PCP Quality Assessment Protocol +--- + +Various objective measures for MRI data quality have been proposed over the years. However, until now no software has allowed researchers to obtain all these measures in the same place with relative ease. The QAP package allows you to obtain spatial and anatomical data quality measures for your own data. Since no standard thresholds demarcating acceptable from unacceptable data are currently existent, you can then compare your data to normative distributions of measures obtained from the [ABIDE](http://fcon_1000.projects.nitrc.org/indi/abide/) and [CoRR](http://fcon_1000.projects.nitrc.org/indi/CoRR/html/index.html) datasets. + +For more information, please see our recent [resting-state poster and associated code]( http://github.com/czarrar/qap_poster). + +**Table of Contents** + +* [Installing the QAP Package](#installing-the-qap-package) +* [Taxonomy of QA Measures](#taxonomy-of-qa-measures) + * [Spatial QA metrics of anatomical data](#spatial-anatomical) + * [Spatial QA metrics of functional data](#spatial-functional) + * [Temporal QA metrics of functional data](#temporal-functional) +* [Normative Metrics (ABIDE and CoRR)](#normative-metrics) +* [Pipeline Configuration YAML Files](#pipeline-configuration-yaml-files) +* [Subject List YAML Files](#subject-list-yaml-files) +* [Running the QAP Pipelines](#running-the-qap-pipelines) +* [Running the QAP Pipelines on AWS Cloud Instances](#running-the-qap-pipelines-on-aws-amazon-cloud-instances) +* [Merging Outputs](#merging-outputs) +* [Generating Reports](#generating-reports) +* [References](#references) + +## Installing the QAP Package + +### System Requirements + +* Any *nix-based operating system capable of running QAP will work, so long as it can run [AFNI](http://afni.nimh.nih.gov), and [FSL](http://fsl.fmrib.ox.ac.uk). +* The total amount of free hard disk space required is 5.7 GB. + +### Application Dependencies + +QAP requires AFNI and FSL to run. Links to installation instructions for AFNI and FSL are listed below: + +* [AFNI Installation](http://afni.nimh.nih.gov/pub/dist/HOWTO/howto/ht00_inst/html) +* [FSL Installation](http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FslInstallation) + +If you are using a Debian-based Linux distribution, you can use `apt-get` by first adding Neurodebian to the apt repository list and then installing the Neurodebian FSL and AFNI packages: + + wget -O- http://neuro.debian.net/lists/$(lsb_release -cs).us-nh.full | tee /etc/apt/sources.list.d/neurodebian.sources.list + apt-key adv --recv-keys --keyserver pgp.mit.edu 2649A5A9 + apt-get update + apt-get install -y fsl-5.0-complete afni + +### Python Dependencies and QAP + +QAP requires Numpy, Scipy, Nipype, Nibabel, Nitime, PyYAML, and pandas to run. If you have `pip`, you may install all of these and QAP itself by typing in the command below: + + pip install qap + +## Taxonomy of QA Measures + +There are three sets of measures that can be run using the QAP software package: + +* Spatial anatomical measures +* Spatial functional measures, which use the mean functional image. +* Temporal functional measures, which use the functional timeseries. + +The following sections will describe the measures belonging to these sets in detail. The label used in the CSV files output by QAP is designated by brackets after the long form measure name. + +To determine subjects that are outliers for any of these measures, run QAP on an array of subjects and take 1.5x or 3x the inter-quartile range. + +### Spatial Anatomical + +* **Contrast to Noise Ratio (CNR) [cnr]:** Calculated as the mean of the gray matter values minus the mean of the white matter values, divided by the standard deviation of the air values. Higher values are better [^1]. +* **Entropy Focus Criterion (EFC) [efc]:** Uses the Shannon entropy of voxel intensities as an indication of ghosting and blurring induced by head motion. Lower values are better [^2]. +* **Foreground to Background Energy Ratio (FBER) [fber]:** Mean energy of image values (i.e., mean of squares) within the head relative to outside the head. Higher values are better. +* **Smoothness of Voxels (FWHM) [fwhm, fwhm_x, fwhm_y, fwhm_z]:** The full-width half maximum (FWHM) of the spatial distribution of the image intensity values in units of voxels. Lower values are better [^3]. +* **Artifact Detection (Qi1) [qi1]:** The proportion of voxels with intensity corrupted by artifacts normalized by the number of voxels in the background. Lower values are better [^4]. +* **Signal-to-Noise Ratio (SNR) [snr]:** The mean of image values within gray matter divided by the standard deviation of the image values within air (i.e., outside the head). Higher values are better [^1]. +* **Summary Measures [fg_mean, fg_std, fg_size, bg_mean, bg_std, bg_size, gm_mean, gm_std, gm_size, wm_mean, wm_std, wm_size, csf_mean, csf_std, csf_size]:** Intermediate measures used to calculate the metrics above. Mean, standard deviation, and mask size are given for foreground, background, white matter, and CSF masks. + +### Spatial Functional + +* **Entropy Focus Criterion [efc]:** Uses the Shannon entropy of voxel intensities as an indication of ghosting and blurring induced by head motion. Lower values are better [^2]. +* **Foreground to Background Energy Ratio [fber]:** Mean energy of image values (i.e., mean of squares) within the head relative to outside the head. Higher values are better. +* **Smoothness of Voxels [fwhm, fwhm_x, fwhm_y, fwhm_z]:** The full-width half maximum (FWHM) of the spatial distribution of the image intensity values in units of voxels. Lower values are better. +* **Ghost to Signal Ratio (GSR) [ghost_x, ghost_y or ghost_z]:** A measure of the mean signal in the ‘ghost’ image (signal present outside the brain due to acquisition in the phase encoding direction) relative to mean signal within the brain. Lower values are better. +* **Summary Measures [fg_mean, fg_std, fg_size, bg_mean, bg_std, bg_size]:** Intermediate measures used to calculate the metrics above. Mean, standard deviation, and mask size are given for foreground and background masks. + + +### Temporal Functional + +* **Standardized DVARS [dvars]:** The spatial standard deviation of the temporal derivative of the data, normalized by the temporal standard deviation and temporal autocorrelation. Lower values are better [^5][^6]. +* **Outlier Detection [outlier]:** The mean fraction of outliers found in each volume using the [3dToutcount](http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dToutcount.html) command from [AFNI](http://afni.nimh.nih.gov/afni). Lower values are better [^7]. +* **Median Distance Index [quality]:** The mean distance (1 – spearman’s rho) between each time-point's volume and the median volume using AFNI’s [3dTqual](http://afni.nimh.nih.gov/afni) command. Lower values are better [^7]. +* **Mean Fractional Displacement - Jenkinson [mean_fd]:** A measure of subject head motion, which compares the motion between the current and previous volumes. This is calculated by summing the absolute value of displacement changes in the x, y and z directions and rotational changes about those three axes. The rotational changes are given distance values based on the changes across the surface of a 80mm radius sphere. Lower values are better [^8][^10]. +* **Number of volumes with FD greater than 0.2mm [num_fd]:** Lower values are better. +* **Percent of volumes with FD greater than 0.2mm [perc_fd]:** Lower values are better. + +## Normative Metrics + +We have gathered QA metrics for two multi-site resting-state datasets: [ABIDE](http://fcon_1000.projects.nitrc.org/indi/abide/) (1,110+ subject across 20+ sites) and [CoRR](http://fcon_1000.projects.nitrc.org/indi/CoRR/html/index.html) (1,400+ subjects across 30+ sites). The QA metrics for these datasets have been made publicly available. They can be used for a variety of applications, for instance, as a comparison to the QA results from your own data. For each link below, please right click and select save as: + +* [ABIDE - Anatomical Measures](https://raw.githubusercontent.com/preprocessed-connectomes-project/quality-assessment-protocol/master/poster_data/abide_anat.csv) +* [ABIDE - Functional Measures](https://raw.githubusercontent.com/preprocessed-connectomes-project/quality-assessment-protocol/master/poster_data/abide_func.csv) +* [CoRR - Anatomical Measures](https://raw.githubusercontent.com/preprocessed-connectomes-project/quality-assessment-protocol/master/poster_data/corr_anat.csv) +* [CoRR - Functional Measures](https://raw.githubusercontent.com/preprocessed-connectomes-project/quality-assessment-protocol/master/poster_data/corr_func.csv) + + +## Pipeline Configuration YAML Files + +Certain pre-processed files derived from the raw data are required to calculate the measures described above. By default, the QAP software package will generate these pre-requisite files given the raw data you have (anatomical/structural scans for the anatomical measures, 4D anatomical+timeseries scans for the functional). A preprocessing pipeline will be constructed to create these files, and this pipeline can be customized with a pipeline configuration YAML file you provide. + +Some examples of customizable features include segmentation thresholds for anatomical preprocessing, and the option to run slice timing correction for functional preprocessing. Computer resource allocation can also be customized using the configuration files, such as dedicating multiple cores/threads to processing. + +Templates for these files are provided in the [`/configs` folder](https://github.com/preprocessed-connectomes-project/quality-assessment-protocol/tree/master/configs) in the QAP main repository directory. Below is a list of options which can be configured for each of the pipelines. + +### General (both types) + +* **num_cores_per_subject**: Number of cores (on a single machine) or slots on a node (cluster/grid) per subject (or per instance of the pipeline). Slots are cores on a cluster/grid node. Dedicating multiple nodes allows each subject's processing pipeline to run certain operations in parallel to save time. +* **num_subjects_at_once**: Similar to *num_cores_per_subject*, except this determines how many pipelines to run at once. +* **output_directory**: The directory to write output files to. +* **working_directory**: The directory to store intermediary processing files in. +* **write_all_outputs**: A boolean option to determine whether or not all files used in the process of calculating the QAP measures will be saved to the output directory or not. If *True*, all outputs will be saved. If *False*, only the csv file containing the measures will be saved. +* **write_report**: A boolean option to determine whether or not to generate report plots and a group measure CSV ([see below](#generating-reports)). If *True*, plots and a CSV will be produced; if *False*, QAP will not produce reports. + +### Anatomical pipelines + +* **template_brain_for_anat**: Template brain to be used during anatomical registration, as a reference. + +### Functional pipelines + +* **start_idx**: This allows you to select an arbitrary range of volumes to include from your 4-D functional timeseries. Enter the number of the first timepoint you wish to include in the analysis. Enter *0* to include the first volume. +* **stop_idx**: This allows you to select an arbitrary range of volumes to include from your 4-D functional timeseries. Enter the number of the last timepoint you wish to include in the analysis. Enter *End* to include the final volume. Enter *0* in start_idx and *End* in stop_idx to include the entire timeseries. +* **slice_timing_correction**: Whether or not to run slice timing correction - *True* or *False*. Interpolates voxel timeseries so that sampling occurs at the same time. +* **ghost_direction**: Allows you to specify the phase encoding (*x* - RL/LR, *y* - AP/PA, *z* - SI/IS, or *all*) used to acquire the scan. Omitting this option will default to *y*. + +Make sure that you multiply *num_cores_per_subject* and *num_subjects_at_once* for the maximum amount of cores that could potentially be used during an anatomical or functional pipeline run. + +## Subject List YAML Files + +### Providing Raw Data + +The QAP pipelines take in subject list YAML (.yml) files as an input. The filepaths to your raw data are defined in these subject lists, and these YAML files can be easily generated using the *qap_raw_data_sublist_generator.py* script included in the QAP software package. After installing the QAP software package, this script can be run from any directory. This subject list generator script assumes a specific directory structure for your input data: + + /data_directory/site_name/subject_id/session_id/scan_id/file.nii.gz + +To make the script parse the above directory structure and generate the subject list YAML file, invoke the following command: + + qap_raw_data_sublist_generator.py {absolute path to site_name directory} {path to where the output YAML file should be stored} {the scan type- can be 'anat' or 'func'} + +These subject lists can also be created or edited by hand if you wish, though this can be cumbersome for larger data sets. For reference, an example of the subject list format follows: + + '1019436': + session_1: + anatomical_scan: + anat_1: /test-data/site_1/1019436/session_1/anat_1/mprage.nii.gz + '2014113': + session_1: + anatomical_scan: + anat_1: /test-data/site_1/2014113/session_1/anat_1/mprage.nii.gz + '3154996': + session_1: + anatomical_scan: + anat_1: /test-data/site_1/3154996/session_1/anat_1/mprage.nii.gz + +Note that *anatomical_scan* is the label for the type of resource (in this case, anatomical raw data for the anatomical spatial QAP measures), and *anat_1* is the name of the scan. There can be multiple scans, which will be combined with subject and session in the output. + +### Providing Already Pre-Processed Data + +Alternatively, if you have already preprocessed some or all of your raw data, you can provide these pre-existing files as inputs directly to the QAP pipelines via your subject list manually. The QAP pipelines will then use these files and skip any pre-processing steps involved in creating them, saving time and allowing you to use your own method of processing your data. If these files were processed using the [C-PAC](http://fcp-indi.github.io/docs/user/index.html) software package, there is a script named *qap_cpac_output_sublist_generator.py* which will create a subject list YAML file pointing to these already generated files. Note that this script will only work for C-PAC runs where FSL is used. Its usage is as follows: + + qap_cpac_output_sublist_generator.py {absolute path to the C-PAC output directory} {path to where the output YAML file should be stored} {the scan type- can be 'anat' or 'func'} {the session format- can be '1','2', or '3', whose corresponding formats are described in more detail below} + +The values for the session format argument can either be: + + 1 - For output organized in the form: /output/pipeline/subject_id/session_id/output/ + 2 - For output organized in the form: /output/pipeline/subject_id/output/ + 3 - For output organized in the form: /output/pipeline/subject_session/output/ + +For example, if C-PAC results were stored in */home/wintermute/output/pipeline_FLIRT/80386_session_1*, you wanted to run anatomical measures, and you wanted to store the subject list in *subj_list.yml*, you would invoke: + + qap_cpac_output_sublist_generator.py /home/wintermute/output/pipeline_FLIRT/80386_session_1 /home/wintermute/qap_analysis/subj_list.yml anat 3 + +Below is a list of intermediary files used in the steps leading to the final QAP measures calculations. If you already have some of these processed for your data, they can be included in the subject list with the label on the left. For example, if you've already deobliqued, reoriented and skull-stripped your anatomical scans, you would list them in your subject list YAML file like so: + + anatomical_brain: /path/to/image.nii.gz + +###Anatomical Spatial measures workflow resources + +* **anatomical_reorient**: anatomical (structural) scan that has been deobliqued and reoriented to RPI (.nii/.nii.gz) +* **anatomical_brain**: deobliqued & reoriented anatomical that has been skull-stripped (.nii/.nii.gz) +* **flirt_affine_xfm**: a warp matrix file output by [FLIRT](http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FLIRT) (.mat) +* **flirt_linear_warped_image**: the [FLIRT](http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/FLIRT)-warped anatomical scan (.nii/.nii.gz) +* **anatomical_csf_mask**: segmentation mask of the anatomical scan's CSF (.nii/.nii.gz) +* **anatomical_gm_mask**: segmentation mask of the anatomical scan's gray matter (.nii/.nii.gz) +* **anatomical_wm_mask**: segmentation mask of the anatomical scan's white matter (.nii/.nii.gz) +* **qap_head_mask**: a whole-skull binarized mask + +In the QAP head mask workflow, we also mask the background immediately in front of the scan participant's mouth. We do this to exclude breathing-induced noise from the calculation for the FBER QAP measure + +### Functional Spatial measures workflow resources + +* **func_motion_correct**: motion-corrected 4-D functional timeseries (.nii/.nii.gz) +* **mcflirt_rel_rms**: if motion correction was performed using FSL's [MCFLIRT](http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/MCFLIRT), use this to specify the path to the motion parameters file. Note that a motion parameters file will only be generated if you pass the *-rmsrel* flag to [MCFLIRT](http://fsl.fmrib.ox.ac.uk/fsl/fslwiki/MCFLIRT). This resource requires that *func_motion_correct* also be defined manually (.rms) +* **functional_brain_mask**: a binarized mask of the functional scan (.nii/.nii.gz) +* **mean_functional**: a 3-D file containing the mean of the functional 4-D timeseries (.nii/.nii.gz) + +### Functional Temporal measures workflow resources + +* **func_motion_correct**: motion-corrected 4-D functional timeseries (.nii/.nii.gz) +* **functional_brain_mask**: a binarized mask of the functional scan (.nii/.nii.gz) +* **coordinate_transformation**: the matrix transformation from base to input coordinates, produced during motion correction (.aff12.1D) + +Note that these are complete lists- obviously, not all intermediary files are required if you choose to provide them. For example, if you provide the skull-stripped *anatomical_brain*, then *anatomical_reorient* would not be necessary, and the pipeline will skip all steps before skull-stripping. Alternatively, if you do not have the *functional_brain_mask* for either of the functional pipelines, providing the *func_motion_correct* file will allow the pipeline to create it for you. Having none of these will simply cause the pipeline to take in the original *functional_scan* and produce all of these files on its own. + +## Running the QAP Pipelines + +There is a launch script for each of these measures, with each one featuring a similar interface. The Python-friendly YAML file format is used for the input subject list and pipeline configuration files. You can use these scripts from the command line, from within iPython, or with AWS Cloud instances. After installing the QAP software package, these scripts can be run from any directory: + +* qap_anatomical_spatial.py +* qap_functional_spatial.py +* qap_functional_temporal.py + +For command-line runs: + + qap_anatomical_spatial.py --sublist {path to subject list YAML file} {path to pipeline configuration YAML file} + +Executing any of the scripts with only the *-h* flag will produce a short help manual listing the command line arguments. + +##Running the QAP Pipelines on AWS Amazon Cloud Instances + +With access to the Amazon Cloud, the QAP measures can be calculated for a large volume of subjects quickly. + +Since there is substantial overlap between the software pre-requisites of QAP and [C-PAC](http://fcp-indi.github.io/docs/user/index.html), it is recommended that you use the C-PAC AMI for your cloud instances. The C-PAC AMI can be used as a base onto which you can [install QAP](#qap). Consult [C-PAC's cloud instructions](http://fcp-indi.github.io/docs/user/cloud.html) for more information on how to use the C-PAC AMI, as well as more general information about AWS. + +If you choose to use another AMI, you will need to install both QAP and its pre-requisites from scratch by [following the instructions above](#installing-the-qap-package). You will also need to configure Starcluster to use the `mnt_config` and `cpac_sge` plugins by following the instructions [here](http://fcp-indi.github.io/docs/user/cloud.html#installing-the-c-pac-starcluster-plug-ins). + +### Generating Your S3 Subject Dictionary File + +The QAP software package comes with a script called *qap_aws_s3_dict_generator.py*, which can be run from any directory once the package is installed. This script requires you to install C-PAC before it will work properly. This script will create a YAML file containing the filepaths to the data stored in your AWS S3 bucket storage. You will need this dictionary YAML file to start an AWS Cloud run for QAP. This script takes in five input parameters: + +* **scan_type**: *anat* or *func*, depending on which QAP measures you will be using the S3 subject dictionary for +* **bucket_name**: the name of your AWS S3 bucket +* **bucket_prefix**: the filepath prefix to the top level of your raw data directory on S3 storage + +For example, if your S3 storage is arranged like so: + + /data/project/raw_data/sub001/session_1/scan_1/file.nii.gz + /data/project/raw_data/sub001/session_1/scan_2/file.nii.gz + /data/project/raw_data/sub002/session_1/scan_1/file.nii.gz + +Then the bucket_prefix would be: + + /data/project/raw_data + + +* **creds_path**: the path to the file containing your AWS credentials +* **outfile_path**: the full filepath for the S3 subject YAML dictionary this script will create + +Once this script is run, it will output the S3 dictionary YAML file, and it will give you the total number of subject-session-scans. Take note of this number, because you will need to list it in your SGE batch file (more below). + +### Setting Up Your SGE File + +Sun Grid Engine (SGE) allows you to parallelize your cloud analyses by having each node in an HPC cluster run QAP on an individual subject. To use SGE on your AWS instance, create a new batch file in your favorite text editor and set up an SGE job in a format similar to below (with settings in curly brackets replaced and the appropriate qap utility used according to your needs): + + #! /bin/bash + #$ -cwd + #$ -S /bin/bash + #$ -V + #$ -t 1-{number of subjects} + #$ -q all.q + #$ -pe mpi_smp {number of CPU cores to use} + #$ -e {absolute path to a file to store standard error from the terminal} + #$ -o /{absolute path to a file to store standard out from the terminal} + source /etc/profile.d/cpac_env.sh + ANAT_S3_DICT={absolute path to S3 subject dictionary YAML file} + ANAT_SP_CONFIG_FILE={absolute path to configuration YAML file} + echo "Start - TASKID " $SGE_TASK_ID " : " $(date) + # Run anatomical spatial qap + qap_anatomical_spatial.py --subj_idx $SGE_TASK_ID --s3_dict_yml $ANAT_S3_DICT $ANAT_SP_CONFIG_FILE + echo "End - TASKID " $SGE_TASK_ID " : " $(date) + +Note that the *mpi_smp* environment is created by the *cpac_sge* Starcluster plug-in mentioned earlier. The *cpac_env.sh* script is a script containing all of the environmental variables used by AFNI and FSL. If you opt to not use the C-PAC AMI, you will need to create a comparable script and have the batch script source it. Submit the job to the SGE scheduler by typing: + + qsub {path to the text file} + +## Merging Outputs + +QAP generates outputs for each subject and session separately. To view a comprehensive summary for all the measures for all the subjects, you will need to merge these separate outputs into a single file. You can do this by running the following command: + + qap_merge_outputs.py {path to qap output directory} + +`qap_merge_outputs.py` will automatically determine if you have calculated anatomical spatial, functional spatial or functional temporal measures. The merged outputs will appear in a file named `qap_anatomical_spatial_{qap output directory name}.csv` in the directory from which the command is run. + +## Generating Reports + +The report functions in the Quality Assessment Protocol allow you to generate optional reports which plot the measures for individual scans, as well as the for the entire group of scans or individuals. These reports aid the visual inspection of scan quality and can be generated by using the [typical workflow commands](#running-the-qap-pipelines). + +In the case of the functional-spatial workflow, instead of just generating separate CSV files that contain each functional scan's spatial QC metrics, the `qap_functional_spatial.py` script will also automatically generate a CSV file that contains the group-level metrics for all scans that were included as inputs. These group-level summary metrics will appear in a file named `qap_functional_spatial.csv` in the output directory designated in the config file. + +In addition, you have the option of generating group-level reports with plots of all the various metrics that contain scores aggregated from all scans/individuals per metric. If this option is selected, there will also be a `qap_functional_spatial.pdf` file which will contain all of the group-level violin plots for each metric. The workflow will also generate report pdfs for each scan (e.g., `qap_functional_spatial_sub-01.pdf`). However, in this case, these reports will also contain any relevant slice mosaics. It is important to note that the individual-level violin plots are the same as those in the group reports, except for the addition of a star, or stars, that represents the score(s) for the scan from that session. The star in these plots denotes where the score for the scan for this individual falls in the distribution of all scores for scans that were included as inputs to the the functional-spatial workflow. If there are several scans per session for this individual, then the stars will be displayed adjacent to each other in the violin plot. + +### Report Examples + +The following image is an example of a report which contains the QC metrics generated by the functional spatial workflow. The group-level data are depicted as violin plots, with each of the plots being a representation of the corresponding values from the column with the same name in the group-level CSV file. In this example, the star denotes where the score for this particular scan falls in the distribution for that metric. The actual value for this scan can be found in the appropriate column of the individual-level CSV file. + +![summary reports](functional_spatial_violins.png) + +The following image is an example of the rendering of the mean EPI image which is provided in the individual-level functional-spatial report. This mean EPI was created by averaging the signal intensity values in each voxel over time. Hence, a 3-dimensional image was created from the 4-dimensional scan and was displayed as a slice mosaic. This image can be used to eyeball the overall quality of the scan, as it will be obvious if there were any large gaps in the image that might indicate that this scan is unusable. + +![EPI example](example_mean_EPI.png) + +The following image is an example of the rendering of the temporal signal-to-noise ratio information from a functional scan, which is provided in the individual-level functional-temporal report. The tSNR plot is similar to the mean EPI plot, in that both metrics reduce the 4-dimensional scan to a representative 3-dimensional volume that is then split and displayed as a stack of axial (horizontal) slices. In this case of the timeseries signal-to-noise ratio, the mean of each voxel's timeseries is also computed and is then divided by the timeseries standard deviation. Hence, the tSNR plot shows the voxels in which one would expect to have SNR good enough for statistical analyses. Differences in tSNR are particularly important for comparing the results from region of interest (ROI) analyses, since any observed functional differences might actually be attributable to systematic differences in SNR across the regions being compared. [You can learn more about the utility of tSNR plots for fMRI analyses here.](http://practicalfmri.blogspot.com.es/2011/01/comparing-fmri-protocols.html) + +![tSNR Example](example_tSNR.png) + +The following image is an example of the framewise displacement that occurred throughout the scan, which is also provided in the individual-level functional-temporal report. This is a temporal motion quality assurance metric and tracks head motions over time, making it easy to determine whether or not the data potentially suffered from significant corruption due to motion. For instance, it is possible to detect if the participant's head was slowly sinking into the cushions in the head coil, or whether the participant was possibly restless or agitated, which would result in several position changes or movement spikes. The framewise displacement is a frame-by-frame representation of the differences between the BOLD signal intensity values of the n and n+1 time points, the n+1 and n+2 timepoints, and so on. The report page for framewise displacement in the functional scan includes both a frame-by-frame plot, as well as a histogram that can be used to visually determine what proportion of timepoints exceeded some pre-set movement threshold (e.g., 0.2 mm). + +![FD Example](example_FD.png) + +Below is an example of the slice mosaic that is provided as a part of the anatomical-spatial workflow. This image is a rendering of the axial slices from the anatomical scan and it is provided in the individual-level report. This slice mosaic can be used to eyeball the quality of the overall signal in the anatomical scan. It should be evident from visual inspection whether there were any problem areas where the signal distortion and/or dropout was large enough to warrant the exclusion of this anatomical can from subsequent analyses. + +![Anatomical](qap_anatomical_example.png) + +### Downloading Data from Your S3 Bucket + +If you ran QAP in the cloud, you will need to download the outputs from S3 before you can merge them. To do this, run the following command: + + qap_download_output_from_S3.py {path to the S3 directory containing subject outputs} {path to AWS key file} {s3 bucket name} {type of measure to download} {directory to download to} + +For example, if you wanted to obtain functional spatial measures from an S3 bucket named `the_big_run` with subject outputs in `subjects/outputs` you would use the following command. + + qap_download_output_from_S3.py subjects/outputs /home/wintermute/Documents/aws-keys.csv the_big_run func_spatial /home/wintermute/qap_outputs + +With the above commands, the outputs will be stored in a directory named `qap_outputs` in the user *wintermute*'s home folder. As with the pipeline commands from earlier, more information on this command's usage can be obtained by running it with the *-h* flag. + +## References + +[^1]: Magnotta, V. A., & Friedman, L. (2006). Measurement of signal-to-noise and contrast-to-noise in the fBIRN multicenter imaging study. Journal of Digital Imaging, 19(2), 140-147. + +[^2]: Atkinson D, Hill DL, Stoyle PN, Summers PE, Keevil SF (1997). Automatic correction of motion artifacts in magnetic resonance images using an entropy focus criterion. IEEE Trans Med Imaging. 16(6):903-10. + +[^3]: Friedman, L., Stern, H., Brown, G. G., Mathalon, D. H., Turner, J., Glover, G. H., ... & Potkin, S. G. (2008). Test–retest and between‐site reliability in a multicenter fMRI study. Human brain mapping, 29(8), 958-972. + +[^4]: Mortamet, B., Bernstein, M. A., Jack, C. R., Gunter, J. L., Ward, C., Britson, P. J., ... & Krueger, G. (2009). Automatic quality assessment in structural brain magnetic resonance imaging. Magnetic Resonance in Medicine, 62(2), 365-372. + +[^5]: Power, J. D., Barnes, K. A., Snyder, A. Z., Schlaggar, B. L. & Petersen, S. E. (2012) Spurious but systematic correlations in functional connectivity MRI networks arise from subject motion. Neuroimage 59, 2142-2154. + +[^6]: Nichols, T. (2012, Oct 28). Standardizing DVARS. Retrieved from http://blogs.warwick.ac.uk/nichols/entry/standardizing_dvars. + +[^7]: Cox, R.W. (1996) AFNI: Software for analysis and visualization of functional magnetic resonance neuroimages. Computers and Biomedical Research, 29:162-173. + +[^8]: Jenkinson, M., Bannister, P., Brady, M., & Smith, S. (2002). Improved optimization for the robust and accurate linear registration and motion correction of brain images. Neuroimage, 17(2), 825-841. + +[^9]: Giannelli, M., Diciotti, S., Tessa, C., & Mascalchi, M. (2010). Characterization of Nyquist ghost in EPI-fMRI acquisition sequences implemented on two clinical 1.5 T MR scanner systems: effect of readout bandwidth and echo spacing. Journal of Applied Clinical Medical Physics, 11(4). + +[^10]: Yan CG, Cheung B, Kelly C, Colcombe S, Craddock RC, Di Martino A, Li Q, Zuo XN, Castellanos FX, Milham MP (2013). A comprehensive assessment of regional variation in the impact of head micromovements on functional connectomics. Neuroimage. 76:183-201. diff --git a/docs/javascripts/BibTex-0.1.2.js b/docs/javascripts/BibTex-0.1.2.js new file mode 100644 index 0000000..d95ea9d --- /dev/null +++ b/docs/javascripts/BibTex-0.1.2.js @@ -0,0 +1,1867 @@ +/*!* + * Javascript BibTex Parser v0.1 + * Copyright (c) 2008 Simon Fraser University + * @author Steve Hannah + * + * + * License: + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * Credits: + * + * This library is a port of the PEAR Structures_BibTex parser written + * in PHP (http://pear.php.net/package/Structures_BibTex). + * + * In order to make porting the parser into javascript easier, I have made + * use of many phpjs functions, which are distributed here under the MIT License: + * + * + * More info at: http://kevin.vanzonneveld.net/techblog/category/php2js + * + * php.js is copyright 2008 Kevin van Zonneveld. + * + * Portions copyright Ates Goral (http://magnetiq.com), Legaev Andrey, + * _argos, Jonas Raoni Soares Silva (http://www.jsfromhell.com), + * Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. L. Rodrigues, Ash + * Searle (http://hexmen.com/blog/), Tyler Akins (http://rumkin.com), mdsjack + * (http://www.mdsjack.bo.it), Alexander Ermolaev + * (http://snippets.dzone.com/user/AlexanderErmolaev), Andrea Giammarchi + * (http://webreflection.blogspot.com), Bayron Guevara, Cord, David, Karol + * Kowalski, Leslie Hoare, Lincoln Ramsay, Mick@el, Nick Callen, Peter-Paul + * Koch (http://www.quirksmode.org/js/beat.html), Philippe Baumann, Steve + * Clay, booeyOH + * + * Licensed under the MIT (MIT-LICENSE.txt) license. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * Synopsis: + * ---------- + * + * This class provides the following functionality: + * 1. Parse BibTex into a logical data javascript data structure. + * 2. Output parsed BibTex entries as HTML, RTF, or BibTex. + * + * + * The following usage instructions have been copyed and adapted from the PHP instructions located + * at http://pear.php.net/manual/en/package.structures.structures-bibtex.intro.php + * Introduction + * -------------- + * Overview + * ---------- + * This package provides methods to access information stored in a BibTex + * file. During parsing it is possible to let the data be validated. In + * addition. the creation of BibTex Strings as well as RTF Strings is also + * supported. A few examples + * + * Example 1. Loading a BibTex File and printing the parsed array + * + * + * + * + * Options + * -------- + * Options can be set either in the constructor or with the method + * setOption(). When setting in the constructor the options are given in an + * associative array. The options are: + * + * - stripDelimiter (default: true) Stripping the delimiter surrounding the entries. + * - validate (default: true) Validation while parsing. + * - unwrap (default: false) Unwrapping entries while parsing. + * - wordWrapWidth (default: false) If set to a number higher one + * that the entries are wrapped after that amount of characters. + * - wordWrapBreak (default: \n) String used to break the line (attached to the line). + * - wordWrapCut (default: 0) If set to zero the line will we + * wrapped at the next possible space, if set to one the line will be + * wrapped exactly after the given amount of characters. + * - removeCurlyBraces (default: false) If set to true Curly Braces will be removed. + * + * Example of setting options in the constructor: + * + * Example 2. Setting options in the constructor + * bibtex = new BibTex({'validate':false, 'unwrap':true}); + * + * + * Example of setting options using the method setOption(): + * + * Example 62-3. Setting options using setOption + * bibtex = new BibTex(); + * bibtex.setOption('validate', false); + * bibtex.setOption('unwrap', true); + * + * Stored Data + * ------------ + * The data is stored in the class variable data. This is a a list where + * each entry is a hash table representing one bibtex-entry. The keys of + * the hash table correspond to the keys used in bibtex and the values are + * the corresponding values. Some of these keys are: + * + * - cite - The key used in a LaTeX source to do the citing. + * - entryType - The type of the entry, like techreport, book and so on. + * - author - One or more authors of the entry. This entry is also a + * list with hash tables representing the authors as entries. The + * author has table is explained later. + * - title - Title of the entry. + * + * Author + * ------ + * As described before the authors are stored in a list. Every entry + * representing one author as a has table. The hash table consits of four + * keys: first, von, last and jr. The keys are explained in the following + * list: + * + * - first - The first name of the author. + * - von - Some names have a 'von' part in their name. This is usually a sign of nobleness. + * - last - The last name of the author. + * - jr - Sometimes a author is the son of his father and has the + * same name, then the value would be jr. The same is true for the + * value sen but vice versa. + * + * Adding an entry + * ---------------- + * To add an entry simply create a hash table with the needed keys and + * values and call the method addEntry(). + * Example 4. Adding an entry + * bibtex = new BibTex(); + * var addarray = {}; + * addarray['entryType'] = 'Article'; + * addarray['cite'] = 'art2'; + * addarray['title'] = 'Titel of the Article'; + * addarray['author'] = []; + * addarray['author'][0]['first'] = 'John'; + * addarray['author'][0]['last'] = 'Doe'; + * addarray['author'][1]['first'] = 'Jane'; + * addarray['author'][1]['last'] = 'Doe'; + * bibtex.addEntry(addarray); + */ + +// ------------BEGIN PHP FUNCTIONS -------------------------------------------------------------- // + +// {{{ array +function array( ) { + // #!#!#!#!# array::$descr1 does not contain valid 'array' at line 258 + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array/ + // + version: 805.1716 + // + original by: d3x + // * example 1: array('Kevin', 'van', 'Zonneveld'); + // * returns 1: ['Kevin', 'van', 'Zonneveld']; + + return Array.prototype.slice.call(arguments); +}// }}} + +// {{{ array_key_exists +function array_key_exists ( key, search ) { + // Checks if the given key or index exists in the array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_key_exists/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Felix Geisendoerfer (http://www.debuggable.com/felix) + // * example 1: array_key_exists('kevin', {'kevin': 'van Zonneveld'}); + // * returns 1: true + + // input sanitation + if( !search || (search.constructor !== Array && search.constructor !== Object) ){ + return false; + } + + return key in search; +}// }}}// {{{ array_keys +function array_keys( input, search_value, strict ) { + // Return all the keys of an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_keys/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: array_keys( {firstname: 'Kevin', surname: 'van Zonneveld'} ); + // * returns 1: {0: 'firstname', 1: 'surname'} + + var tmp_arr = new Array(), strict = !!strict, include = true, cnt = 0; + + for ( key in input ){ + include = true; + if ( search_value != undefined ) { + if( strict && input[key] !== search_value ){ + include = false; + } else if( input[key] != search_value ){ + include = false; + } + } + + if( include ) { + tmp_arr[cnt] = key; + cnt++; + } + } + + return tmp_arr; +}// }}} + +// {{{ in_array +function in_array(needle, haystack, strict) { + // Checks if a value exists in an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_in_array/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: true + + var found = false, key, strict = !!strict; + + for (key in haystack) { + if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) { + found = true; + break; + } + } + + return found; +}// }}} + +// {{{ sizeof +function sizeof ( mixed_var, mode ) { + // Alias of count() + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_sizeof/ + // + version: 804.1712 + // + original by: Philip Peterson + // - depends on: count + // * example 1: sizeof([[0,0],[0,-4]], 'COUNT_RECURSIVE'); + // * returns 1: 6 + // * example 2: sizeof({'one' : [1,2,3,4,5]}, 'COUNT_RECURSIVE'); + // * returns 2: 6 + + return count( mixed_var, mode ); +}// }}} + +// {{{ count +function count( mixed_var, mode ) { + // Count elements in an array, or properties in an object + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_count/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: _argos + // * example 1: count([[0,0],[0,-4]], 'COUNT_RECURSIVE'); + // * returns 1: 6 + // * example 2: count({'one' : [1,2,3,4,5]}, 'COUNT_RECURSIVE'); + // * returns 2: 6 + + var key, cnt = 0; + + if( mode == 'COUNT_RECURSIVE' ) mode = 1; + if( mode != 1 ) mode = 0; + + for (key in mixed_var){ + cnt++; + if( mode==1 && mixed_var[key] && (mixed_var[key].constructor === Array || mixed_var[key].constructor === Object) ){ + cnt += count(mixed_var[key], 1); + } + } + + return cnt; +}// }}} + +// {{{ explode +function explode( delimiter, string, limit ) { + // Split a string by string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_explode/ + // + version: 805.1715 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: kenneth + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: d3x + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: explode(' ', 'Kevin van Zonneveld'); + // * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'} + // * example 2: explode('=', 'a=bc=d', 2); + // * returns 2: ['a', 'bc=d'] + + var emptyArray = { 0: '' }; + + // third argument is not required + if ( arguments.length < 2 + || typeof arguments[0] == 'undefined' + || typeof arguments[1] == 'undefined' ) + { + return null; + } + + if ( delimiter === '' + || delimiter === false + || delimiter === null ) + { + return false; + } + + if ( typeof delimiter == 'function' + || typeof delimiter == 'object' + || typeof string == 'function' + || typeof string == 'object' ) + { + return emptyArray; + } + + if ( delimiter === true ) { + delimiter = '1'; + } + + if (!limit) { + return string.toString().split(delimiter.toString()); + } else { + // support for limit argument + var splitted = string.toString().split(delimiter.toString()); + var partA = splitted.splice(0, limit - 1); + var partB = splitted.join(delimiter.toString()); + partA.push(partB); + return partA; + } +}// }}} + +// {{{ implode +function implode( glue, pieces ) { + // Join array elements with a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_implode/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: _argos + // * example 1: implode(' ', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: 'Kevin van Zonneveld' + + return ( ( pieces instanceof Array ) ? pieces.join ( glue ) : pieces ); +}// }}} + +// {{{ join +function join( glue, pieces ) { + // Alias of implode() + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_join/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: implode + // * example 1: join(' ', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: 'Kevin van Zonneveld' + + return implode( glue, pieces ); +}// }}} + +// {{{ split +function split( delimiter, string ) { + // Split string into array by regular expression + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_split/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: explode + // * example 1: split(' ', 'Kevin van Zonneveld'); + // * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'} + + return explode( delimiter, string ); +}// }}} + +// {{{ str_replace +function str_replace(search, replace, subject) { + // Replace all occurrences of the search string with the replacement string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_str_replace/ + // + version: 805.3114 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Gabriel Paderni + // + improved by: Philip Peterson + // + improved by: Simon Willison (http://simonwillison.net) + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // - depends on: is_array + // * example 1: str_replace(' ', '.', 'Kevin van Zonneveld'); + // * returns 1: 'Kevin.van.Zonneveld' + // * example 2: str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars'); + // * returns 2: 'hemmo, mars' + + var f = search, r = replace, s = subject; + var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length; + + while (j = 0, i--) { + while (s[i] = s[i].split(f[j]).join(ra ? r[j] || "" : r[0]), ++j in f){}; + }; + + return sa ? s : s[0]; +}// }}} + +// {{{ strlen +function strlen( string ){ + // Get string length + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strlen/ + // + version: 805.1616 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Sakimori + // * example 1: strlen('Kevin van Zonneveld'); + // * returns 1: 19 + + return ("" + string).length; +}// }}} + +// {{{ strpos +function strpos( haystack, needle, offset){ + // Find position of first occurrence of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strpos/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strpos('Kevin van Zonneveld', 'e', 5); + // * returns 1: 14 + + var i = haystack.indexOf( needle, offset ); // returns -1 + return i >= 0 ? i : false; +}// }}} + +// {{{ strrpos +function strrpos( haystack, needle, offset){ + // Find position of last occurrence of a char in a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strrpos/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strrpos('Kevin van Zonneveld', 'e'); + // * returns 1: 16 + + var i = haystack.lastIndexOf( needle, offset ); // returns -1 + return i >= 0 ? i : false; +}// }}} + +// {{{ strtolower +function strtolower( str ) { + // Make a string lowercase + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strtolower/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strtolower('Kevin van Zonneveld'); + // * returns 1: 'kevin van zonneveld' + + return str.toLowerCase(); +}// }}} + +// {{{ strtoupper +function strtoupper( str ) { + // Make a string uppercase + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strtoupper/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strtoupper('Kevin van Zonneveld'); + // * returns 1: 'KEVIN VAN ZONNEVELD' + + return str.toUpperCase(); +}// }}} + +// {{{ substr +function substr( f_string, f_start, f_length ) { + // Return part of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_substr/ + // + version: 804.1712 + // + original by: Martijn Wieringa + // * example 1: substr('abcdef', 0, -1); + // * returns 1: 'abcde' + + if(f_start < 0) { + f_start += f_string.length; + } + + if(f_length == undefined) { + f_length = f_string.length; + } else if(f_length < 0){ + f_length += f_string.length; + } else { + f_length += f_start; + } + + if(f_length < f_start) { + f_length = f_start; + } + + return f_string.substring(f_start, f_length); +}// }}} + +// {{{ trim +function trim( str, charlist ) { + // Strip whitespace (or other characters) from the beginning and end of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_trim/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: mdsjack (http://www.mdsjack.bo.it) + // + improved by: Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev) + // + input by: Erkekjetter + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: DxGx + // + improved by: Steven Levithan (http://blog.stevenlevithan.com) + // * example 1: trim(' Kevin van Zonneveld '); + // * returns 1: 'Kevin van Zonneveld' + // * example 2: trim('Hello World', 'Hdle'); + // * returns 2: 'o Wor' + if (!str) { return ''; } + var whitespace; + + if(!charlist){ + whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; + } else{ + whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1'); + } + + for (var i = 0; i < str.length; i++) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(i); + break; + } + } + for (i = str.length - 1; i >= 0; i--) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(0, i + 1); + break; + } + } + return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''; +}// }}} + + +// {{{ wordwrap +function wordwrap( str, int_width, str_break, cut ) { + // Wraps a string to a given number of characters + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_wordwrap/ + // + version: 804.1715 + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Nick Callen + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // * example 1: wordwrap('Kevin van Zonneveld', 6, '|', true); + // * returns 1: 'Kevin |van |Zonnev|eld' + + var m = int_width, b = str_break, c = cut; + var i, j, l, s, r; + + if(m < 1) { + return str; + } + for(i = -1, l = (r = str.split("\n")).length; ++i < l; r[i] += s) { + for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : "")){ + j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length; + } + } + + return r.join("\n"); +}// }}} + +// {{{ is_string +function is_string( mixed_var ){ + // Find whether the type of a variable is string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_string/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: is_string('23'); + // * returns 1: true + // * example 2: is_string(23.5); + // * returns 2: false + + return (typeof( mixed_var ) == 'string'); +}// }}} + + +// {{{ ord +function ord( string ) { + // Return ASCII value of character + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_ord/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: ord('K'); + // * returns 1: 75 + + return string.charCodeAt(0); +}// }}} + +// {{{ array_unique +function array_unique( array ) { + // Removes duplicate values from an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_unique/ + // + version: 805.211 + // + original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com) + // + input by: duncan + // + bufixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: array_unique(['Kevin','Kevin','van','Zonneveld']); + // * returns 1: ['Kevin','van','Zonneveld'] + + var p, i, j, tmp_arr = array; + for(i = tmp_arr.length; i;){ + for(p = --i; p > 0;){ + if(tmp_arr[i] === tmp_arr[--p]){ + for(j = p; --p && tmp_arr[i] === tmp_arr[p];); + i -= tmp_arr.splice(p + 1, j - p).length; + } + } + } + + return tmp_arr; +}// }}} + +// {{{ print_r +function print_r( array, return_val ) { + // Prints human-readable information about a variable + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_print_r/ + // + version: 805.2023 + // + original by: Michael White (http://crestidg.com) + // + improved by: Ben Bryan + // * example 1: print_r(1, true); + // * returns 1: 1 + + var output = "", pad_char = " ", pad_val = 4; + + var formatArray = function (obj, cur_depth, pad_val, pad_char) { + if (cur_depth > 0) { + cur_depth++; + } + + var base_pad = repeat_char(pad_val*cur_depth, pad_char); + var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char); + var str = ""; + + if (obj instanceof Array || obj instanceof Object) { + str += "Array\n" + base_pad + "(\n"; + for (var key in obj) { + if (obj[key] instanceof Array || obj[key] instanceof Object) { + str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char); + } else { + str += thick_pad + "["+key+"] => " + obj[key] + "\n"; + } + } + str += base_pad + ")\n"; + } else { + str = obj.toString(); + } + + return str; + }; + + var repeat_char = function (len, pad_char) { + var str = ""; + for(var i=0; i < len; i++) { + str += pad_char; + }; + return str; + }; + output = formatArray(array, 0, pad_val, pad_char); + + if (return_val !== true) { + document.write("
" + output + "
"); + return true; + } else { + return output; + } +}// }}} +// {{{ is_array +function is_array( mixed_var ) { + // Finds whether a variable is an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Legaev Andrey + // + bugfixed by: Cord + // * example 1: is_array(['Kevin', 'van', 'Zonneveld']); + // * returns 1: true + // * example 2: is_array('Kevin van Zonneveld'); + // * returns 2: false + + return ( mixed_var instanceof Array ); +}// }}} + +//------------END PHP FUNCTIONS -------------------------------------------------------------- // + +/** + * BibTex + * + * A class which provides common methods to access and + * create Strings in BibTex format+ + * Example 1: Parsing a BibTex File and returning the number of entries + * + * bibtex = new BibTex(); + * bibtex.content = '....'; + * + * bibtex.parse(); + * print "There are "+bibtex.amount()+" entries"; + * + * Example 2: Parsing a BibTex File and getting all Titles + * + * bibtex = new BibTex(); + * bibtex.content="..."; + * bibtex.parse(); + * for (var i in bibtex.data) { + * alert( bibtex.data[i]['title']+"
"); + * } + *
+ * Example 3: Adding an entry and printing it in BibTex Format + * + * bibtex = new BibTex(); + * addarray = {} + * addarray['entryType'] = 'Article'; + * addarray['cite'] = 'art2'; + * addarray['title'] = 'Titel2'; + * addarray['author'] = []; + * addarray['author'][0]['first'] = 'John'; + * addarray['author'][0]['last'] = 'Doe'; + * addarray['author'][1]['first'] = 'Jane'; + * addarray['author'][1]['last'] = 'Doe'; + * bibtex.addEntry(addarray); + * alert( nl2br(bibtex.bibTex())); + * + * + * @category Structures + * @package BibTex + * @author Steve Hannah + * @adapted-from Structures_BibTex by Elmar Pitschke + * @copyright 2008 Simon Fraser University + * @license http://www.gnu.org/licenses/lgpl.html + * @version Release: 0.1 + * @link http://webgroup.fas.sfu.ca/projects/JSBibTexParser + */ +function BibTex(options) +{ + + if ( typeof options == 'undefined' ) options = {}; + /** + * Array with the BibTex Data + * + * @access public + * @var array + */ + this.data; + /** + * String with the BibTex content + * + * @access public + * @var string + */ + this.content; + /** + * Array with possible Delimiters for the entries + * + * @access private + * @var array + */ + this._delimiters; + /** + * Array to store warnings + * + * @access public + * @var array + */ + this.warnings; + /** + * Run-time configuration options + * + * @access private + * @var array + */ + this._options; + /** + * RTF Format String + * + * @access public + * @var string + */ + this.rtfstring; + /** + * HTML Format String + * + * @access public + * @var string + */ + this.htmlstring; + /** + * Array with the "allowed" entry types + * + * @access public + * @var array + */ + this.allowedEntryTypes; + /** + * Author Format Strings + * + * @access public + * @var string + */ + this.authorstring; + + this._delimiters = {'"':'"', + '{':'}'}; + this.data = []; + this.content = ''; + //this._stripDelimiter = stripDel; + //this._validate = val; + this.warnings = []; + this._options = { + 'stripDelimiter' : true, + 'validate' : true, + 'unwrap' : false, + 'wordWrapWidth' : false, + 'wordWrapBreak' : "\n", + 'wordWrapCut' : 0, + 'removeCurlyBraces' : false, + 'extractAuthors' : true + }; + for (option in options) { + test = this.setOption(option, options[option]); + if (this.isError(test)) { + //Currently nothing is done here, but it could for example raise an warning + } + } + this.rtfstring = 'AUTHORS, "{\b TITLE}", {\i JOURNAL}, YEAR'; + this.htmlstring = 'AUTHORS, "TITLE", JOURNAL, YEAR
'; + this.allowedEntryTypes = array( + 'article', + 'book', + 'booklet', + 'confernce', + 'inbook', + 'incollection', + 'inproceedings', + 'manual', + 'masterthesis', + 'misc', + 'phdthesis', + 'proceedings', + 'techreport', + 'unpublished' + ); + this.authorstring = 'VON LAST, JR, FIRST'; + +} + + +BibTex.prototype = { + + /** + * Constructor + * + * @access public + * @return void + */ + + + /** + * Sets run-time configuration options + * + * @access public + * @param string option option name + * @param mixed value value for the option + * @return mixed true on success PEAR_Error on failure + */ + setOption : function(option, value) + { + ret = true; + if (array_key_exists(option, this._options)) { + this._options[option] = value; + } else { + ret = this.raiseError('Unknown option '+option); + } + return ret; + }, + + /** + * Reads a give BibTex File + * + * @access public + * @param string filename Name of the file + * @return mixed true on success PEAR_Error on failure + * + function loadFile(filename) + { + if (file_exists(filename)) { + if ((this.content = @file_get_contents(filename)) === false) { + return PEAR::raiseError('Could not open file '+filename); + } else { + this._pos = 0; + this._oldpos = 0; + return true; + } + } else { + return PEAR::raiseError('Could not find file '+filename); + } + } + */ + /** + * Parses what is stored in content and clears the content if the parsing is successfull+ + * + * @access public + * @return boolean true on success and PEAR_Error if there was a problem + */ + parse: function() + { + //alert("starting to parse"); + //The amount of opening braces is compared to the amount of closing braces + //Braces inside comments are ignored + this.warnings = []; + this.data = []; + var valid = true; + var open = 0; + var entry = false; + var charv = ''; + var lastchar = ''; + var buffer = ''; + for (var i = 0; i < strlen(this.content); i++) { + charv = substr(this.content, i, 1); + if ((0 != open) && ('@' == charv)) { + if (!this._checkAt(buffer)) { + this._generateWarning('WARNING_MISSING_END_BRACE', '', buffer); + //To correct the data we need to insert a closing brace + charv = '}'; + i--; + } + } + if ((0 == open) && ('@' == charv)) { //The beginning of an entry + entry = true; + } else if (entry && ('{' == charv) && ('\\' != lastchar)) { //Inside an entry and non quoted brace is opening + open++; + } else if (entry && ('}' == charv) && ('\\' != lastchar)) { //Inside an entry and non quoted brace is closing + open--; + if (open < 0) { //More are closed than opened + valid = false; + } + if (0 == open) { //End of entry + entry = false; + var entrydata = this._parseEntry(buffer); + if (!entrydata) { + /** + * This is not yet used+ + * We are here if the Entry is either not correct or not supported+ + * But this should already generate a warning+ + * Therefore it should not be necessary to do anything here + */ + } else { + this.data[this.data.length] = entrydata; + } + buffer = ''; + } + } + if (entry) { //Inside entry + buffer += charv; + } + lastchar = charv; + } + //If open is one it may be possible that the last ending brace is missing + if (1 == open) { + entrydata = this._parseEntry(buffer); + if (!entrydata) { + valid = false; + } else { + this.data[this.data.length] = entrydata; + buffer = ''; + open = 0; + } + } + //At this point the open should be zero + if (0 != open) { + valid = false; + } + //Are there Multiple entries with the same cite? + if (this._options['validate']) { + cites = []; + for (var i=0; i< this.data.length; i++ ) { + cites[cites.length] = this.data[i]['cite']; + } + unique = array_unique(cites); + if (cites.length != sizeof(unique)) { //Some values have not been unique! + notuniques = []; + for (var i = 0; i < cites.length; i++) { + if ('' == unique[i]) { + notuniques[notuniques.length] = cites[i]; + } + } + this._generateWarning('WARNING_MULTIPLE_ENTRIES', implode(',',notuniques)); + } + } + //alert("finished parsing"); + if (valid) { + this.content = ''; + return true; + } else { + return this.raiseError('Unbalanced parenthesis'); + } + }, + + /** + * Extracting the data of one content + * + * The parse function splits the content into its entries+ + * Then every entry is parsed by this function+ + * It parses the entry backwards+ + * First the last '=' is searched and the value extracted from that+ + * A copy is made of the entry if warnings should be generated+ This takes quite + * some memory but it is needed to get good warnings+ If nor warnings are generated + * then you don have to worry about memory+ + * Then the last ',' is searched and the field extracted from that+ + * Again the entry is shortened+ + * Finally after all field:value pairs the cite and type is extraced and the + * authors are splitted+ + * If there is a problem false is returned+ + * + * @access private + * @param string entry The entry + * @return array The representation of the entry or false if there is a problem + */ + '_parseEntry': function(entry) + { + var entrycopy = ''; + if (this._options['validate']) { + entrycopy = entry; //We need a copy for printing the warnings + } + var ret = {}; + if ('@string' == strtolower(substr(entry, 0, 7))) { + //String are not yet supported! + if (this._options['validate']) { + this._generateWarning('STRING_ENTRY_NOT_YET_SUPPORTED', '', entry+'}'); + } + } else if ('@preamble' == strtolower(substr(entry, 0, 9))) { + //Preamble not yet supported! + if (this._options['validate']) { + this._generateWarning('PREAMBLE_ENTRY_NOT_YET_SUPPORTED', '', entry+'}'); + } + } else { + //Parsing all fields + while (strrpos(entry,'=') !== false) { + position = strrpos(entry, '='); + //Checking that the equal sign is not quoted or is not inside a equation (For example in an abstract) + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + if (proceed) { + proceed = this._checkEqualSign(entry, position); + } + while (!proceed) { + substring = substr(entry, 0, position); + position = strrpos(substring,'='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + if (proceed) { + proceed = this._checkEqualSign(entry, position); + } + } + + value = trim(substr(entry, position+1)); + entry = substr(entry, 0, position); + + if (',' == substr(value, strlen(value)-1, 1)) { + value = substr(value, 0, -1); + } + if (this._options['validate']) { + this._validateValue(value, entrycopy); + } + if (this._options['stripDelimiter']) { + value = this._stripDelimiter(value); + } + if (this._options['unwrap']) { + value = this._unwrap(value); + } + if (this._options['removeCurlyBraces']) { + value = this._removeCurlyBraces(value); + } + position = strrpos(entry, ','); + field = strtolower(trim(substr(entry, position+1))); + ret[field] = value; + entry = substr(entry, 0, position); + } + //Parsing cite and entry type + var arr = entry.split('{'); + ret['cite'] = trim(arr[1]); + ret['entryType'] = strtolower(trim(arr[0])); + //alert(array_keys(ret)); + if ('@' == ret['entryType'].substring(0,1)) { + ret['entryType'] = substr(ret['entryType'], 1); + } + if (this._options['validate']) { + if (!this._checkAllowedEntryType(ret['entryType'])) { + this._generateWarning('WARNING_NOT_ALLOWED_ENTRY_TYPE', ret['entryType'], entry+'}'); + } + } + //Handling the authors + if (in_array('author', array_keys(ret)) && this._options['extractAuthors']) { + ret['author'] = this._extractAuthors(ret['author']); + } + } + return ret; + }, + + /** + * Checking whether the position of the '=' is correct + * + * Sometimes there is a problem if a '=' is used inside an entry (for example abstract)+ + * This method checks if the '=' is outside braces then the '=' is correct and true is returned+ + * If the '=' is inside braces it contains to a equation and therefore false is returned+ + * + * @access private + * @param string entry The text of the whole remaining entry + * @param int the current used place of the '=' + * @return bool true if the '=' is correct, false if it contains to an equation + */ + '_checkEqualSign': function(entry, position) + { + var ret = true; + //This is getting tricky + //We check the string backwards until the position and count the closing an opening braces + //If we reach the position the amount of opening and closing braces should be equal + var length = strlen(entry); + var open = 0; + for (var i = length-1; i >= position; i--) { + precedingchar = substr(entry, i-1, 1); + charv = substr(entry, i, 1); + if (('{' == charv) && ('\\' != precedingchar)) { + open++; + } + if (('}' == charv) && ('\\' != precedingchar)) { + open--; + } + } + if (0 != open) { + ret = false; + } + //There is still the posibility that the entry is delimited by double quotes+ + //Then it is possible that the braces are equal even if the '=' is in an equation+ + if (ret) { + entrycopy = trim(entry); + lastchar = substr(entrycopy,strlen(entrycopy)-1,1); + if (',' == lastchar) { + lastchar = substr(entrycopy, strlen(entrycopy)-2, 1); + } + if ('"' == lastchar) { + //The return value is set to false + //If we find the closing " before the '=' it is set to true again+ + //Remember we begin to search the entry backwards so the " has to show up twice - ending and beginning delimiter + ret = false; + found = 0; + for (var i = length; i >= position; i--) { + precedingchar = substr(entry, i-1, 1); + charv = substr(entry, i, 1); + if (('"' == charv) && ('\\' != precedingchar)) { + found++; + } + if (2 == found) { + ret = true; + break; + } + } + } + } + return ret; + }, + + /** + * Checking if the entry type is allowed + * + * @access private + * @param string entry The entry to check + * @return bool true if allowed, false otherwise + */ + '_checkAllowedEntryType': function(entry) + { + return in_array(entry, this.allowedEntryTypes); + }, + + /** + * Checking whether an at is outside an entry + * + * Sometimes an entry misses an entry brace+ Then the at of the next entry seems to be + * inside an entry+ This is checked here+ When it is most likely that the at is an opening + * at of the next entry this method returns true+ + * + * @access private + * @param string entry The text of the entry until the at + * @return bool true if the at is correct, false if the at is likely to begin the next entry+ + */ + '_checkAt': function(entry) + { + var ret = false; + var opening = array_keys(this._delimiters); + var closing = array_values(this._delimiters); + //Getting the value (at is only allowd in values) + if (strrpos(entry,'=') !== false) { + position = strrpos(entry, '='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + while (!proceed) { + substring = substr(entry, 0, position); + position = strrpos(substring,'='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + } + value = trim(substr(entry, position+1)); + open = 0; + charv = ''; + lastchar = ''; + for (var i = 0; i < strlen(value); i++) { + charv = substr(this.content, i, 1); + if (in_array(charv, opening) && ('\\' != lastchar)) { + open++; + } else if (in_array(charv, closing) && ('\\' != lastchar)) { + open--; + } + lastchar = charv; + } + //if open is grater zero were are inside an entry + if (open>0) { + ret = true; + } + } + return ret; + }, + + /** + * Stripping Delimiter + * + * @access private + * @param string entry The entry where the Delimiter should be stripped from + * @return string Stripped entry + */ + '_stripDelimiter': function(entry) + { + var beginningdels = array_keys(this._delimiters); + var ength = strlen(entry); + var firstchar = substr(entry, 0, 1); + var lastchar = substr(entry, -1, 1); + while (in_array(firstchar, beginningdels)) { //The first character is an opening delimiter + if (lastchar == this._delimiters[firstchar]) { //Matches to closing Delimiter + entry = substr(entry, 1, -1); + } else { + break; + } + firstchar = substr(entry, 0, 1); + lastchar = substr(entry, -1, 1); + } + return entry; + }, + + /** + * Unwrapping entry + * + * @access private + * @param string entry The entry to unwrap + * @return string unwrapped entry + */ + '_unwrap': function(entry) + { + entry = entry.replace(/\s+/, ' '); + return trim(entry); + }, + + /** + * Wordwrap an entry + * + * @access private + * @param string entry The entry to wrap + * @return string wrapped entry + */ + '_wordwrap': function(entry) + { + if ( (''!=entry) && (is_string(entry)) ) { + entry = wordwrap(entry, this._options['wordWrapWidth'], this._options['wordWrapBreak'], this._options['wordWrapCut']); + } + return entry; + }, + + /** + * Extracting the authors + * + * @access private + * @param string entry The entry with the authors + * @return array the extracted authors + */ + '_extractAuthors': function(entry) { + entry = this._unwrap(entry); + var authorarray = entry.split(' and '); + for (var i = 0; i < authorarray.length; i++) { + var author = trim(authorarray[i]); + /*The first version of how an author could be written (First von Last) + has no commas in it*/ + var first = ''; + var von = ''; + var last = ''; + var jr = ''; + if (strpos(author, ',') === false) { + var tmparray = author.split(' |~'); + var size = tmparray.length; + if (1 == size) { //There is only a last + last = tmparray[0]; + } else if (2 == size) { //There is a first and a last + first = tmparray[0]; + last = tmparray[1]; + } else { + var invon = false; + var inlast = false; + for (var j=0; j<(size-1); j++) { + if (inlast) { + last += ' '+tmparray[j]; + } else if (invon) { + casev = this._determineCase(tmparray[j]); + if (this.isError(casev)) { + // IGNORE? + } else if ((0 == casev) || (-1 == casev)) { //Change from von to last + //You only change when there is no more lower case there + islast = true; + for (var k=(j+1); k<(size-1); k++) { + futurecase = this._determineCase(tmparray[k]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == futurecase) { + islast = false; + } + } + if (islast) { + inlast = true; + if (-1 == casev) { //Caseless belongs to the last + last += ' '+tmparray[j]; + } else { + von += ' '+tmparray[j]; + } + } else { + von += ' '+tmparray[j]; + } + } else { + von += ' '+tmparray[j]; + } + } else { + var casev = this._determineCase(tmparray[j]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == casev) { //Change from first to von + invon = true; + von += ' '+tmparray[j]; + } else { + first += ' '+tmparray[j]; + } + } + } + //The last entry is always the last! + last += ' '+tmparray[size-1]; + } + } else { //Version 2 and 3 + var tmparray = []; + tmparray = explode(',', author); + //The first entry must contain von and last + vonlastarray = []; + vonlastarray = explode(' ', tmparray[0]); + size = sizeof(vonlastarray); + if (1==size) { //Only one entry.got to be the last + last = vonlastarray[0]; + } else { + inlast = false; + for (var j=0; j<(size-1); j++) { + if (inlast) { + last += ' '+vonlastarray[j]; + } else { + if (0 != (this._determineCase(vonlastarray[j]))) { //Change from von to last + islast = true; + for (var k=(j+1); k<(size-1); k++) { + this._determineCase(vonlastarray[k]); + casev = this._determineCase(vonlastarray[k]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == casev) { + islast = false; + } + } + if (islast) { + inlast = true; + last += ' '+vonlastarray[j]; + } else { + von += ' '+vonlastarray[j]; + } + } else { + von += ' '+vonlastarray[j]; + } + } + } + last += ' '+vonlastarray[size-1]; + } + //Now we check if it is version three (three entries in the array (two commas) + if (3==tmparray.length) { + jr = tmparray[1]; + } + //Everything in the last entry is first + first = tmparray[tmparray.length-1]; + } + authorarray[i] = {'first':trim(first), 'von':trim(von), 'last':trim(last), 'jr':trim(jr)}; + } + return authorarray; + }, + + /** + * Case Determination according to the needs of BibTex + * + * To parse the Author(s) correctly a determination is needed + * to get the Case of a word+ There are three possible values: + * - Upper Case (return value 1) + * - Lower Case (return value 0) + * - Caseless (return value -1) + * + * @access private + * @param string word + * @return int The Case or PEAR_Error if there was a problem + */ + '_determineCase': function(word) { + var ret = -1; + var trimmedword = trim (word); + /*We need this variable+ Without the next of would not work + (trim changes the variable automatically to a string!)*/ + if (is_string(word) && (strlen(trimmedword) > 0)) { + var i = 0; + var found = false; + var openbrace = 0; + while (!found && (i <= strlen(word))) { + var letter = substr(trimmedword, i, 1); + var ordv = ord(letter); + if (ordv == 123) { //Open brace + openbrace++; + } + if (ordv == 125) { //Closing brace + openbrace--; + } + if ((ordv>=65) && (ordv<=90) && (0==openbrace)) { //The first character is uppercase + ret = 1; + found = true; + } else if ( (ordv>=97) && (ordv<=122) && (0==openbrace) ) { //The first character is lowercase + ret = 0; + found = true; + } else { //Not yet found + i++; + } + } + } else { + ret = this.raiseError('Could not determine case on word: '+word); + } + return ret; + }, + + + 'isError': function(obj){ + return ( typeof(obj) == 'Object' && obj.isError == 1 ); + + }, + + /** + * Validation of a value + * + * There may be several problems with the value of a field+ + * These problems exist but do not break the parsing+ + * If a problem is detected a warning is appended to the array warnings+ + * + * @access private + * @param string entry The entry aka one line which which should be validated + * @param string wholeentry The whole BibTex Entry which the one line is part of + * @return void + */ + '_validateValue': function(entry, wholeentry) + { + //There is no @ allowed if the entry is enclosed by braces + if ( entry.match(/^{.*@.*}/)) { + this._generateWarning('WARNING_AT_IN_BRACES', entry, wholeentry); + } + //No escaped " allowed if the entry is enclosed by double quotes + if (entry.match(/^\".*\\".*\"/)) { + this._generateWarning('WARNING_ESCAPED_DOUBLE_QUOTE_INSIDE_DOUBLE_QUOTES', entry, wholeentry); + } + //Amount of Braces is not correct + var open = 0; + var lastchar = ''; + var charv = ''; + for (var i = 0; i < strlen(entry); i++) { + charv = substr(entry, i, 1); + if (('{' == charv) && ('\\' != lastchar)) { + open++; + } + if (('}' == charv) && ('\\' != lastchar)) { + open--; + } + lastchar = charv; + } + if (0 != open) { + this._generateWarning('WARNING_UNBALANCED_AMOUNT_OF_BRACES', entry, wholeentry); + } + }, + + /** + * Remove curly braces from entry + * + * @access private + * @param string value The value in which curly braces to be removed + * @param string Value with removed curly braces + */ + '_removeCurlyBraces': function(value) + { + //First we save the delimiters + var beginningdels = array_keys(this._delimiters); + var firstchar = substr(value, 0, 1); + var lastchar = substr(value, -1, 1); + var begin = ''; + var end = ''; + while (in_array(firstchar, beginningdels)) { //The first character is an opening delimiter + if (lastchar == this._delimiters[firstchar]) { //Matches to closing Delimiter + begin += firstchar; + end += lastchar; + value = substr(value, 1, -1); + } else { + break; + } + firstchar = substr(value, 0, 1); + lastchar = substr(value, -1, 1); + } + //Now we get rid of the curly braces + var pattern = '/([^\\\\])\{(+*?[^\\\\])\}/'; + var replacement = '12'; + value = value.replace(/([^\\\\])\{(.*?[^\\\\])\}/, replacement); + //Reattach delimiters + value = begin+value+end; + return value; + }, + + /** + * Generates a warning + * + * @access private + * @param string type The type of the warning + * @param string entry The line of the entry where the warning occurred + * @param string wholeentry OPTIONAL The whole entry where the warning occurred + */ + '_generateWarning': function(type, entry, wholeentry) + { + if ( typeof wholeentry == 'undefined' ) wholeentry = ''; + var warning = {}; + warning['warning'] = type; + warning['entry'] = entry; + warning['wholeentry'] = wholeentry; + this.warnings[this.warnings.length] = warning; + }, + + /** + * Cleares all warnings + * + * @access public + */ + 'clearWarnings': function() + { + this.warnings = array(); + }, + + /** + * Is there a warning? + * + * @access public + * @return true if there is, false otherwise + */ + 'hasWarning': function() + { + if (sizeof(this.warnings)>0) return true; + else return false; + }, + + /** + * Returns the amount of available BibTex entries + * + * @access public + * @return int The amount of available BibTex entries + */ + 'amount': function() + { + return sizeof(this.data); + }, + /** + * Returns the author formatted + * + * The Author is formatted as setted in the authorstring + * + * @access private + * @param array array Author array + * @return string the formatted author string + */ + '_formatAuthor': function(array) + { + if (!array_key_exists('von', array)) { + array['von'] = ''; + } else { + array['von'] = trim(array['von']); + } + if (!array_key_exists('last', array)) { + array['last'] = ''; + } else { + array['last'] = trim(array['last']); + } + if (!array_key_exists('jr', array)) { + array['jr'] = ''; + } else { + array['jr'] = trim(array['jr']); + } + if (!array_key_exists('first', array)) { + array['first'] = ''; + } else { + array['first'] = trim(array['first']); + } + ret = this.authorstring; + ret = str_replace("VON", array['von'], ret); + ret = str_replace("LAST", array['last'], ret); + ret = str_replace("JR", array['jr'], ret); + ret = str_replace("FIRST", array['first'], ret); + return trim(ret); + }, + + /** + * Converts the stored BibTex entries to a BibTex String + * + * In the field list, the author is the last field+ + * + * @access public + * @return string The BibTex string + */ + 'bibTex': function() + { + var bibtex = ''; + for (var i=0 ; i0) { + val = this._wordWrap(val); + } + if (!in_array(key, array('cite','entryType','author'))) { + bibtex += "\t"+key+' = {'+val+"},\n"; + } + } + //Author + if (array_key_exists('author', entry)) { + if (this._options['extractAuthors']) { + tmparray = []; //In this array the authors are saved and the joind with an and + for (j in entry['author']) { + var authorentry = entry['author'][j]; + tmparray[tmparray.length] = this._formatAuthor(authorentry); + } + author = join(' and ', tmparray); + } else { + author = entry['author']; + } + } else { + author = ''; + } + bibtex += "\tauthor = {"+author+"}\n"; + bibtex+="}\n\n"; + } + return bibtex; + }, + + /** + * Adds a new BibTex entry to the data + * + * @access public + * @param array newentry The new data to add + * @return void + */ + 'addEntry': function(newentry) + { + this.data[this.data.length] = newentry; + }, + + /** + * Returns statistic + * + * This functions returns a hash table+ The keys are the different + * entry types and the values are the amount of these entries+ + * + * @access public + * @return array Hash Table with the data + */ + 'getStatistic': function() + { + var ret = array(); + for (var i=0; i + * + * + * License: + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * Credits: + * + * This library is a port of the PEAR Structures_BibTex parser written + * in PHP (http://pear.php.net/package/Structures_BibTex). + * + * In order to make porting the parser into javascript easier, I have made + * use of many phpjs functions, which are distributed here under the MIT License: + * + * + * More info at: http://kevin.vanzonneveld.net/techblog/category/php2js + * + * php.js is copyright 2008 Kevin van Zonneveld. + * + * Portions copyright Ates Goral (http://magnetiq.com), Legaev Andrey, + * _argos, Jonas Raoni Soares Silva (http://www.jsfromhell.com), + * Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. L. Rodrigues, Ash + * Searle (http://hexmen.com/blog/), Tyler Akins (http://rumkin.com), mdsjack + * (http://www.mdsjack.bo.it), Alexander Ermolaev + * (http://snippets.dzone.com/user/AlexanderErmolaev), Andrea Giammarchi + * (http://webreflection.blogspot.com), Bayron Guevara, Cord, David, Karol + * Kowalski, Leslie Hoare, Lincoln Ramsay, Mick@el, Nick Callen, Peter-Paul + * Koch (http://www.quirksmode.org/js/beat.html), Philippe Baumann, Steve + * Clay, booeyOH + * + * Licensed under the MIT (MIT-LICENSE.txt) license. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * Synopsis: + * ---------- + * + * This class provides the following functionality: + * 1. Parse BibTex into a logical data javascript data structure. + * 2. Output parsed BibTex entries as HTML, RTF, or BibTex. + * + * + * The following usage instructions have been copyed and adapted from the PHP instructions located + * at http://pear.php.net/manual/en/package.structures.structures-bibtex.intro.php + * Introduction + * -------------- + * Overview + * ---------- + * This package provides methods to access information stored in a BibTex + * file. During parsing it is possible to let the data be validated. In + * addition. the creation of BibTex Strings as well as RTF Strings is also + * supported. A few examples + * + * Example 1. Loading a BibTex File and printing the parsed array + * + * + * + * + * Options + * -------- + * Options can be set either in the constructor or with the method + * setOption(). When setting in the constructor the options are given in an + * associative array. The options are: + * + * - stripDelimiter (default: true) Stripping the delimiter surrounding the entries. + * - validate (default: true) Validation while parsing. + * - unwrap (default: false) Unwrapping entries while parsing. + * - wordWrapWidth (default: false) If set to a number higher one + * that the entries are wrapped after that amount of characters. + * - wordWrapBreak (default: \n) String used to break the line (attached to the line). + * - wordWrapCut (default: 0) If set to zero the line will we + * wrapped at the next possible space, if set to one the line will be + * wrapped exactly after the given amount of characters. + * - removeCurlyBraces (default: false) If set to true Curly Braces will be removed. + * + * Example of setting options in the constructor: + * + * Example 2. Setting options in the constructor + * bibtex = new BibTex({'validate':false, 'unwrap':true}); + * + * + * Example of setting options using the method setOption(): + * + * Example 62-3. Setting options using setOption + * bibtex = new BibTex(); + * bibtex.setOption('validate', false); + * bibtex.setOption('unwrap', true); + * + * Stored Data + * ------------ + * The data is stored in the class variable data. This is a a list where + * each entry is a hash table representing one bibtex-entry. The keys of + * the hash table correspond to the keys used in bibtex and the values are + * the corresponding values. Some of these keys are: + * + * - cite - The key used in a LaTeX source to do the citing. + * - entryType - The type of the entry, like techreport, book and so on. + * - author - One or more authors of the entry. This entry is also a + * list with hash tables representing the authors as entries. The + * author has table is explained later. + * - title - Title of the entry. + * + * Author + * ------ + * As described before the authors are stored in a list. Every entry + * representing one author as a has table. The hash table consits of four + * keys: first, von, last and jr. The keys are explained in the following + * list: + * + * - first - The first name of the author. + * - von - Some names have a 'von' part in their name. This is usually a sign of nobleness. + * - last - The last name of the author. + * - jr - Sometimes a author is the son of his father and has the + * same name, then the value would be jr. The same is true for the + * value sen but vice versa. + * + * Adding an entry + * ---------------- + * To add an entry simply create a hash table with the needed keys and + * values and call the method addEntry(). + * Example 4. Adding an entry + * bibtex = new BibTex(); + * var addarray = {}; + * addarray['entryType'] = 'Article'; + * addarray['cite'] = 'art2'; + * addarray['title'] = 'Titel of the Article'; + * addarray['author'] = []; + * addarray['author'][0]['first'] = 'John'; + * addarray['author'][0]['last'] = 'Doe'; + * addarray['author'][1]['first'] = 'Jane'; + * addarray['author'][1]['last'] = 'Doe'; + * bibtex.addEntry(addarray); + */ +function array(){return Array.prototype.slice.call(arguments);}function array_key_exists(key,search){if(!search||(search.constructor!==Array&&search.constructor!==Object)){return false;}return key in search;}function array_keys(input,search_value,strict){var tmp_arr=new Array(),strict=!!strict,include=true,cnt=0;for(key in input){include=true;if(search_value!=undefined){if(strict&&input[key]!==search_value){include=false;}else{if(input[key]!=search_value){include=false;}}}if(include){tmp_arr[cnt]=key;cnt++;}}return tmp_arr;}function in_array(needle,haystack,strict){var found=false,key,strict=!!strict;for(key in haystack){if((strict&&haystack[key]===needle)||(!strict&&haystack[key]==needle)){found=true;break;}}return found;}function sizeof(mixed_var,mode){return count(mixed_var,mode);}function count(mixed_var,mode){var key,cnt=0;if(mode=="COUNT_RECURSIVE"){mode=1;}if(mode!=1){mode=0;}for(key in mixed_var){cnt++;if(mode==1&&mixed_var[key]&&(mixed_var[key].constructor===Array||mixed_var[key].constructor===Object)){cnt+=count(mixed_var[key],1);}}return cnt;}function explode(delimiter,string,limit){var emptyArray={0:""};if(arguments.length<2||typeof arguments[0]=="undefined"||typeof arguments[1]=="undefined"){return null;}if(delimiter===""||delimiter===false||delimiter===null){return false;}if(typeof delimiter=="function"||typeof delimiter=="object"||typeof string=="function"||typeof string=="object"){return emptyArray;}if(delimiter===true){delimiter="1";}if(!limit){return string.toString().split(delimiter.toString());}else{var splitted=string.toString().split(delimiter.toString());var partA=splitted.splice(0,limit-1);var partB=splitted.join(delimiter.toString());partA.push(partB);return partA;}}function implode(glue,pieces){return((pieces instanceof Array)?pieces.join(glue):pieces);}function join(glue,pieces){return implode(glue,pieces);}function split(delimiter,string){return explode(delimiter,string);}function str_replace(search,replace,subject){var f=search,r=replace,s=subject;var ra=is_array(r),sa=is_array(s),f=[].concat(f),r=[].concat(r),i=(s=[].concat(s)).length;while(j=0,i--){while(s[i]=s[i].split(f[j]).join(ra?r[j]||"":r[0]),++j in f){}}return sa?s:s[0];}function strlen(string){return(""+string).length;}function strpos(haystack,needle,offset){var i=haystack.indexOf(needle,offset);return i>=0?i:false;}function strrpos(haystack,needle,offset){var i=haystack.lastIndexOf(needle,offset);return i>=0?i:false;}function strtolower(str){return str.toLowerCase();}function strtoupper(str){return str.toUpperCase();}function substr(f_string,f_start,f_length){if(f_start<0){f_start+=f_string.length;}if(f_length==undefined){f_length=f_string.length;}else{if(f_length<0){f_length+=f_string.length;}else{f_length+=f_start;}}if(f_length=0;i--){if(whitespace.indexOf(str.charAt(i))===-1){str=str.substring(0,i+1);break;}}return whitespace.indexOf(str.charAt(0))===-1?str:"";}function wordwrap(str,int_width,str_break,cut){var m=int_width,b=str_break,c=cut;var i,j,l,s,r;if(m<1){return str;}for(i=-1,l=(r=str.split("\n")).length;++im;r[i]+=s.slice(0,j)+((s=s.slice(j)).length?b:"")){j=c==2||(j=s.slice(0,m+1).match(/\S*(\s)?$/))[1]?m:j.input.length-j[0].length||c==1&&m||j.input.length+(j=s.slice(m).match(/^\S*/)).input.length;}}return r.join("\n");}function is_string(mixed_var){return(typeof(mixed_var)=="string");}function ord(string){return string.charCodeAt(0);}function array_unique(array){var p,i,j,tmp_arr=array;for(i=tmp_arr.length;i;){for(p=--i;p>0;){if(tmp_arr[i]===tmp_arr[--p]){for(j=p;--p&&tmp_arr[i]===tmp_arr[p];){}i-=tmp_arr.splice(p+1,j-p).length;}}}return tmp_arr;}function print_r(array,return_val){var output="",pad_char=" ",pad_val=4;var formatArray=function(obj,cur_depth,pad_val,pad_char){if(cur_depth>0){cur_depth++;}var base_pad=repeat_char(pad_val*cur_depth,pad_char);var thick_pad=repeat_char(pad_val*(cur_depth+1),pad_char);var str="";if(obj instanceof Array||obj instanceof Object){str+="Array\n"+base_pad+"(\n";for(var key in obj){if(obj[key] instanceof Array||obj[key] instanceof Object){str+=thick_pad+"["+key+"] => "+formatArray(obj[key],cur_depth+1,pad_val,pad_char);}else{str+=thick_pad+"["+key+"] => "+obj[key]+"\n";}}str+=base_pad+")\n";}else{str=obj.toString();}return str;};var repeat_char=function(len,pad_char){var str="";for(var i=0;i"+output+"");return true;}else{return output;}}function is_array(mixed_var){return(mixed_var instanceof Array);}function BibTex(options){if(typeof options=="undefined"){options={};}this.data;this.content;this._delimiters;this.warnings;this._options;this.rtfstring;this.htmlstring;this.allowedEntryTypes;this.authorstring;this._delimiters={'"':'"',"{":"}"};this.data=[];this.content="";this.warnings=[];this._options={stripDelimiter:true,validate:true,unwrap:false,wordWrapWidth:false,wordWrapBreak:"\n",wordWrapCut:0,removeCurlyBraces:false,extractAuthors:true};for(option in options){test=this.setOption(option,options[option]);if(this.isError(test)){}}this.rtfstring='AUTHORS, "{\b TITLE}", {i JOURNAL}, YEAR';this.htmlstring='AUTHORS, "TITLE", JOURNAL, YEAR
';this.allowedEntryTypes=array("article","book","booklet","confernce","inbook","incollection","inproceedings","manual","masterthesis","misc","phdthesis","proceedings","techreport","unpublished");this.authorstring="VON LAST, JR, FIRST";}BibTex.prototype={setOption:function(option,value){ret=true;if(array_key_exists(option,this._options)){this._options[option]=value;}else{ret=this.raiseError("Unknown option "+option);}return ret;},parse:function(){this.warnings=[];this.data=[];var valid=true;var open=0;var entry=false;var charv="";var lastchar="";var buffer="";for(var i=0;i=position;i--){precedingchar=substr(entry,i-1,1);charv=substr(entry,i,1);if(("{"==charv)&&("\\"!=precedingchar)){open++;}if(("}"==charv)&&("\\"!=precedingchar)){open--;}}if(0!=open){ret=false;}if(ret){entrycopy=trim(entry);lastchar=substr(entrycopy,strlen(entrycopy)-1,1);if(","==lastchar){lastchar=substr(entrycopy,strlen(entrycopy)-2,1);}if('"'==lastchar){ret=false;found=0;for(var i=length;i>=position;i--){precedingchar=substr(entry,i-1,1);charv=substr(entry,i,1);if(('"'==charv)&&("\\"!=precedingchar)){found++;}if(2==found){ret=true;break;}}}}return ret;},_checkAllowedEntryType:function(entry){return in_array(entry,this.allowedEntryTypes);},_checkAt:function(entry){var ret=false;var opening=array_keys(this._delimiters);var closing=array_values(this._delimiters);if(strrpos(entry,"=")!==false){position=strrpos(entry,"=");proceed=true;if(substr(entry,position-1,1)=="\\"){proceed=false;}while(!proceed){substring=substr(entry,0,position);position=strrpos(substring,"=");proceed=true;if(substr(entry,position-1,1)=="\\"){proceed=false;}}value=trim(substr(entry,position+1));open=0;charv="";lastchar="";for(var i=0;i0){ret=true;}}return ret;},_stripDelimiter:function(entry){var beginningdels=array_keys(this._delimiters);var ength=strlen(entry);var firstchar=substr(entry,0,1);var lastchar=substr(entry,-1,1);while(in_array(firstchar,beginningdels)){if(lastchar==this._delimiters[firstchar]){entry=substr(entry,1,-1);}else{break;}firstchar=substr(entry,0,1);lastchar=substr(entry,-1,1);}return entry;},_unwrap:function(entry){entry=entry.replace(/\s+/," ");return trim(entry);},_wordwrap:function(entry){if((""!=entry)&&(is_string(entry))){entry=wordwrap(entry,this._options.wordWrapWidth,this._options.wordWrapBreak,this._options.wordWrapCut);}return entry;},_extractAuthors:function(entry){entry=this._unwrap(entry);var authorarray=entry.split(" and ");for(var i=0;i0)){var i=0;var found=false;var openbrace=0;while(!found&&(i<=strlen(word))){var letter=substr(trimmedword,i,1);var ordv=ord(letter);if(ordv==123){openbrace++;}if(ordv==125){openbrace--;}if((ordv>=65)&&(ordv<=90)&&(0==openbrace)){ret=1;found=true;}else{if((ordv>=97)&&(ordv<=122)&&(0==openbrace)){ret=0;found=true;}else{i++;}}}}else{ret=this.raiseError("Could not determine case on word: "+word);}return ret;},isError:function(obj){return(typeof(obj)=="Object"&&obj.isError==1);},_validateValue:function(entry,wholeentry){if(entry.match(/^{.*@.*}/)){this._generateWarning("WARNING_AT_IN_BRACES",entry,wholeentry);}if(entry.match(/^\".*\\".*\"/)){this._generateWarning("WARNING_ESCAPED_DOUBLE_QUOTE_INSIDE_DOUBLE_QUOTES",entry,wholeentry);}var open=0;var lastchar="";var charv="";for(var i=0;i0){return true;}else{return false;}},amount:function(){return sizeof(this.data);},_formatAuthor:function(array){if(!array_key_exists("von",array)){array.von="";}else{array.von=trim(array.von);}if(!array_key_exists("last",array)){array.last="";}else{array.last=trim(array.last);}if(!array_key_exists("jr",array)){array.jr="";}else{array.jr=trim(array.jr);}if(!array_key_exists("first",array)){array.first="";}else{array.first=trim(array.first);}ret=this.authorstring;ret=str_replace("VON",array.von,ret);ret=str_replace("LAST",array.last,ret);ret=str_replace("JR",array.jr,ret);ret=str_replace("FIRST",array.first,ret);return trim(ret);},bibTex:function(){var bibtex="";for(var i=0;i0){val=this._wordWrap(val);}if(!in_array(key,array("cite","entryType","author"))){bibtex+="\t"+key+" = {"+val+"},\n";}}if(array_key_exists("author",entry)){if(this._options.extractAuthors){tmparray=[];for(j in entry.author){var authorentry=entry.author[j];tmparray[tmparray.length]=this._formatAuthor(authorentry);}author=join(" and ",tmparray);}else{author=entry.author;}}else{author="";}bibtex+="\tauthor = {"+author+"}\n";bibtex+="}\n\n";}return bibtex;},addEntry:function(newentry){this.data[this.data.length]=newentry;},getStatistic:function(){var ret=array();for(var i=0;i\n";return ret;}}; +/*! + * File: jquery.dataTables.min.js + * Version: 1.6.2 + * Author: Allan Jardine (www.sprymedia.co.uk) + * Info: www.datatables.net + * + * Copyright 2008-2010 Allan Jardine, all rights reserved. + * + * This source file is free software, under either the GPL v2 license or a + * BSD style license, as supplied with this software. + * + * This source file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details. + */ +(function($){$.fn.dataTableSettings=[];var _aoSettings=$.fn.dataTableSettings;$.fn.dataTableExt={};var _oExt=$.fn.dataTableExt;_oExt.sVersion="1.6.2";_oExt.iApiIndex=0;_oExt.oApi={};_oExt.afnFiltering=[];_oExt.aoFeatures=[];_oExt.ofnSearch={};_oExt.afnSortData=[];_oExt.oStdClasses={sPagePrevEnabled:"paginate_enabled_previous",sPagePrevDisabled:"paginate_disabled_previous",sPageNextEnabled:"paginate_enabled_next",sPageNextDisabled:"paginate_disabled_next",sPageJUINext:"",sPageJUIPrev:"",sPageButton:"paginate_button",sPageButtonActive:"paginate_active",sPageButtonStaticDisabled:"paginate_button",sPageFirst:"first",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sSortJUIAsc:"",sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:""};_oExt.oJUIClasses={sPagePrevEnabled:"fg-button ui-state-default ui-corner-left",sPagePrevDisabled:"fg-button ui-state-default ui-corner-left ui-state-disabled",sPageNextEnabled:"fg-button ui-state-default ui-corner-right",sPageNextDisabled:"fg-button ui-state-default ui-corner-right ui-state-disabled",sPageJUINext:"ui-icon ui-icon-circle-arrow-e",sPageJUIPrev:"ui-icon ui-icon-circle-arrow-w",sPageButton:"fg-button ui-state-default",sPageButtonActive:"fg-button ui-state-default ui-state-disabled",sPageButtonStaticDisabled:"fg-button ui-state-default ui-state-disabled",sPageFirst:"first ui-corner-tl ui-corner-bl",sPagePrevious:"previous",sPageNext:"next",sPageLast:"last ui-corner-tr ui-corner-br",sStripOdd:"odd",sStripEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate fg-buttonset fg-buttonset-multi paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",sSortAsc:"ui-state-default",sSortDesc:"ui-state-default",sSortable:"ui-state-default",sSortableAsc:"ui-state-default",sSortableDesc:"ui-state-default",sSortableNone:"ui-state-default",sSortColumn:"sorting_",sSortJUIAsc:"css_right ui-icon ui-icon-triangle-1-n",sSortJUIDesc:"css_right ui-icon ui-icon-triangle-1-s",sSortJUI:"css_right ui-icon ui-icon-carat-2-n-s",sSortJUIAscAllowed:"css_right ui-icon ui-icon-carat-1-n",sSortJUIDescAllowed:"css_right ui-icon ui-icon-carat-1-s"};_oExt.oPagination={two_button:{fnInit:function(oSettings,nPaging,fnCallbackDraw){var nPrevious,nNext,nPreviousInner,nNextInner;if(!oSettings.bJUI){nPrevious=document.createElement("div");nNext=document.createElement("div");}else{nPrevious=document.createElement("a");nNext=document.createElement("a");nNextInner=document.createElement("span");nNextInner.className=oSettings.oClasses.sPageJUINext;nNext.appendChild(nNextInner);nPreviousInner=document.createElement("span");nPreviousInner.className=oSettings.oClasses.sPageJUIPrev;nPrevious.appendChild(nPreviousInner);}nPrevious.className=oSettings.oClasses.sPagePrevDisabled;nNext.className=oSettings.oClasses.sPageNextDisabled;nPrevious.title=oSettings.oLanguage.oPaginate.sPrevious;nNext.title=oSettings.oLanguage.oPaginate.sNext;nPaging.appendChild(nPrevious);nPaging.appendChild(nNext);$(nPrevious).click(function(){if(oSettings.oApi._fnPageChange(oSettings,"previous")){fnCallbackDraw(oSettings);}});$(nNext).click(function(){if(oSettings.oApi._fnPageChange(oSettings,"next")){fnCallbackDraw(oSettings);}});$(nPrevious).bind("selectstart",function(){return false;});$(nNext).bind("selectstart",function(){return false;});if(oSettings.sTableId!==""&&typeof oSettings.aanFeatures.p=="undefined"){nPaging.setAttribute("id",oSettings.sTableId+"_paginate");nPrevious.setAttribute("id",oSettings.sTableId+"_previous");nNext.setAttribute("id",oSettings.sTableId+"_next");}},fnUpdate:function(oSettings,fnCallbackDraw){if(!oSettings.aanFeatures.p){return;}var an=oSettings.aanFeatures.p;for(var i=0,iLen=an.length;i=(iPages-iPageCountHalf)){iStartButton=iPages-iPageCount+1;iEndButton=iPages;}else{iStartButton=iCurrentPage-Math.ceil(iPageCount/2)+1;iEndButton=iStartButton+iPageCount-1;}}}for(i=iStartButton;i<=iEndButton;i++){if(iCurrentPage!=i){sList+=''+i+"";}else{sList+=''+i+"";}}var an=oSettings.aanFeatures.p;var anButtons,anStatic,nPaginateList;var fnClick=function(){var iTarget=(this.innerHTML*1)-1;oSettings._iDisplayStart=iTarget*oSettings._iDisplayLength;fnCallbackDraw(oSettings);return false;};var fnFalse=function(){return false;};for(i=0,iLen=an.length;iy)?1:0));},"string-desc":function(a,b){var x=a.toLowerCase();var y=b.toLowerCase();return((xy)?-1:0));},"html-asc":function(a,b){var x=a.replace(/<.*?>/g,"").toLowerCase();var y=b.replace(/<.*?>/g,"").toLowerCase();return((xy)?1:0));},"html-desc":function(a,b){var x=a.replace(/<.*?>/g,"").toLowerCase();var y=b.replace(/<.*?>/g,"").toLowerCase();return((xy)?-1:0));},"date-asc":function(a,b){var x=Date.parse(a);var y=Date.parse(b);if(isNaN(x)){x=Date.parse("01/01/1970 00:00:00");}if(isNaN(y)){y=Date.parse("01/01/1970 00:00:00");}return x-y;},"date-desc":function(a,b){var x=Date.parse(a);var y=Date.parse(b);if(isNaN(x)){x=Date.parse("01/01/1970 00:00:00");}if(isNaN(y)){y=Date.parse("01/01/1970 00:00:00");}return y-x;},"numeric-asc":function(a,b){var x=a=="-"?0:a;var y=b=="-"?0:b;return x-y;},"numeric-desc":function(a,b){var x=a=="-"?0:a;var y=b=="-"?0:b;return y-x;}};_oExt.aTypes=[function(sData){if(typeof sData=="number"){return"numeric";}else{if(typeof sData.charAt!="function"){return null;}}var sValidFirstChars="0123456789-";var sValidChars="0123456789.";var Char;var bDecimal=false;Char=sData.charAt(0);if(sValidFirstChars.indexOf(Char)==-1){return null;}for(var i=1;i=parseInt(sThat,10);};this.fnSort=function(aaSort){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);oSettings.aaSorting=aaSort;_fnSort(oSettings);};this.fnSortListener=function(nNode,iColumn,fnCallback){_fnSortAttachListener(_fnSettingsFromNode(this[_oExt.iApiIndex]),nNode,iColumn,fnCallback);};this.fnAddData=function(mData,bRedraw){if(mData.length===0){return[];}var aiReturn=[];var iTest;var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);if(typeof mData[0]=="object"){for(var i=0;i=oSettings.aiDisplay.length){oSettings._iDisplayStart-=oSettings._iDisplayLength;if(oSettings._iDisplayStart<0){oSettings._iDisplayStart=0;}}_fnCalculateEnd(oSettings);_fnDraw(oSettings);var aData=oSettings.aoData[iAODataIndex]._aData.slice();if(typeof bNullRow!="undefined"&&bNullRow===true){oSettings.aoData[iAODataIndex]=null;}return aData;};this.fnClearTable=function(bRedraw){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);_fnClearTable(oSettings);if(typeof bRedraw=="undefined"||bRedraw){_fnDraw(oSettings);}};this.fnOpen=function(nTr,sHtml,sClass){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);this.fnClose(nTr);var nNewRow=document.createElement("tr");var nNewCell=document.createElement("td");nNewRow.appendChild(nNewCell);nNewCell.className=sClass;nNewCell.colSpan=_fnVisbleColumns(oSettings);nNewCell.innerHTML=sHtml;var nTrs=$("tbody tr",oSettings.nTable);if($.inArray(nTr,nTrs)!=-1){$(nNewRow).insertAfter(nTr);}if(!oSettings.oFeatures.bServerSide){oSettings.aoOpenRows.push({nTr:nNewRow,nParent:nTr});}return nNewRow;};this.fnClose=function(nTr){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);for(var i=0;itr",oSettings.nTable)[0];var nTrFoot=$("tfoot:eq(0)>tr",oSettings.nTable)[0];var anTheadTh=[];var anTfootTh=[];for(i=0;i=_fnVisbleColumns(oSettings)){nTrHead.appendChild(anTheadTh[iCol]);if(nTrFoot){nTrFoot.appendChild(anTfootTh[iCol]);}for(i=0,iLen=oSettings.aoData.length;itd:eq("+iBefore+")",oSettings.aoData[i].nTr)[0]);}}oSettings.aoColumns[iCol].bVisible=true;}else{nTrHead.removeChild(anTheadTh[iCol]);if(nTrFoot){nTrFoot.removeChild(anTfootTh[iCol]);}anTds=_fnGetTdNodes(oSettings);for(i=0,iLen=oSettings.aoData.length;i=oSettings.fnRecordsDisplay())?0:oSettings.iInitDisplayStart;oSettings.iInitDisplayStart=-1;_fnCalculateEnd(oSettings);}if(oSettings.aiDisplay.length!==0){var iStart=oSettings._iDisplayStart;var iEnd=oSettings._iDisplayEnd;if(oSettings.oFeatures.bServerSide){iStart=0;iEnd=oSettings.aoData.length;}for(var j=iStart;jtr",oSettings.nTable)[0],_fnGetDataMaster(oSettings),oSettings._iDisplayStart,oSettings.fnDisplayEnd(),oSettings.aiDisplay);}if(typeof oSettings.fnFooterCallback=="function"){oSettings.fnFooterCallback($("tfoot:eq(0)>tr",oSettings.nTable)[0],_fnGetDataMaster(oSettings),oSettings._iDisplayStart,oSettings.fnDisplayEnd(),oSettings.aiDisplay);}var nBody=oSettings.nTable.getElementsByTagName("tbody");if(nBody[0]){var nTrs=nBody[0].childNodes;for(i=nTrs.length-1;i>=0;i--){nTrs[i].parentNode.removeChild(nTrs[i]);}for(i=0,iLen=anRows.length;i"){nInsertNode=nInsertNode.parentNode;}else{if(cOption=="l"&&oSettings.oFeatures.bPaginate&&oSettings.oFeatures.bLengthChange){nTmp=_fnFeatureHtmlLength(oSettings);iPushFeature=1;}else{if(cOption=="f"&&oSettings.oFeatures.bFilter){nTmp=_fnFeatureHtmlFilter(oSettings);iPushFeature=1;}else{if(cOption=="r"&&oSettings.oFeatures.bProcessing){nTmp=_fnFeatureHtmlProcessing(oSettings);iPushFeature=1;}else{if(cOption=="t"){nTmp=oSettings.nTable;iPushFeature=1;}else{if(cOption=="i"&&oSettings.oFeatures.bInfo){nTmp=_fnFeatureHtmlInfo(oSettings);iPushFeature=1;}else{if(cOption=="p"&&oSettings.oFeatures.bPaginate){nTmp=_fnFeatureHtmlPaginate(oSettings);iPushFeature=1;}else{if(_oExt.aoFeatures.length!==0){var aoFeatures=_oExt.aoFeatures;for(var k=0,kLen=aoFeatures.length;k';var jqFilter=$("input",nFilter);jqFilter.val(oSettings.oPreviousSearch.sSearch.replace('"',"""));jqFilter.keyup(function(e){var n=oSettings.aanFeatures.f;for(var i=0,iLen=n.length;i=0;i--){var sData=_fnDataToSearch(oSettings.aoData[oSettings.aiDisplay[i]]._aData[iColumn],oSettings.aoColumns[iColumn].sType);if(!rpSearch.test(sData)){oSettings.aiDisplay.splice(i,1);iIndexCorrector++;}}}function _fnFilter(oSettings,sInput,iForce,bEscapeRegex){var i;if(typeof iForce=="undefined"||iForce===null){iForce=0;}if(_oExt.afnFiltering.length!==0){iForce=1;}var asSearch=bEscapeRegex?_fnEscapeRegex(sInput).split(" "):sInput.split(" ");var sRegExpString="^(?=.*?"+asSearch.join(")(?=.*?")+").*$";var rpSearch=new RegExp(sRegExpString,"i");if(sInput.length<=0){oSettings.aiDisplay.splice(0,oSettings.aiDisplay.length);oSettings.aiDisplay=oSettings.aiDisplayMaster.slice();}else{if(oSettings.aiDisplay.length==oSettings.aiDisplayMaster.length||oSettings.oPreviousSearch.sSearch.length>sInput.length||iForce==1||sInput.indexOf(oSettings.oPreviousSearch.sSearch)!==0){oSettings.aiDisplay.splice(0,oSettings.aiDisplay.length);_fnBuildSearchArray(oSettings,1);for(i=0;i/g,"");}else{if(typeof sData=="string"){return sData.replace(/\n/g," ");}}}return sData;}function _fnSort(oSettings,bApplyClasses){var aaSort=[];var oSort=_oExt.oSort;var aoData=oSettings.aoData;var iDataSort;var iDataType;var i,j,jLen;if(!oSettings.oFeatures.bServerSide&&(oSettings.aaSorting.length!==0||oSettings.aaSortingFixed!==null)){if(oSettings.aaSortingFixed!==null){aaSort=oSettings.aaSortingFixed.concat(oSettings.aaSorting);}else{aaSort=oSettings.aaSorting.slice();}for(i=0;i=iColumns){for(i=0;i=0?oSettings._iDisplayStart-oSettings._iDisplayLength:0;if(oSettings._iDisplayStart<0){oSettings._iDisplayStart=0;}}else{if(sAction=="next"){if(oSettings._iDisplayLength>=0){if(oSettings._iDisplayStart+oSettings._iDisplayLength=0){var iPages=parseInt((oSettings.fnRecordsDisplay()-1)/oSettings._iDisplayLength,10)+1;oSettings._iDisplayStart=(iPages-1)*oSettings._iDisplayLength;}else{oSettings._iDisplayStart=0;}}else{alert("DataTables warning: unknown paging action: "+sAction);}}}}return iOldStart!=oSettings._iDisplayStart;}function _fnFeatureHtmlInfo(oSettings){var nInfo=document.createElement("div");nInfo.className=oSettings.oClasses.sInfo;if(typeof oSettings.aanFeatures.i=="undefined"){oSettings.aoDrawCallback.push({fn:_fnUpdateInfo,sName:"information"});if(oSettings.sTableId!==""){nInfo.setAttribute("id",oSettings.sTableId+"_info");}}return nInfo;}function _fnUpdateInfo(oSettings){if(!oSettings.oFeatures.bInfo||oSettings.aanFeatures.i.length===0){return;}var nFirst=oSettings.aanFeatures.i[0];if(oSettings.fnRecordsDisplay()===0&&oSettings.fnRecordsDisplay()==oSettings.fnRecordsTotal()){nFirst.innerHTML=oSettings.oLanguage.sInfoEmpty+oSettings.oLanguage.sInfoPostFix;}else{if(oSettings.fnRecordsDisplay()===0){nFirst.innerHTML=oSettings.oLanguage.sInfoEmpty+" "+oSettings.oLanguage.sInfoFiltered.replace("_MAX_",oSettings.fnRecordsTotal())+oSettings.oLanguage.sInfoPostFix;}else{if(oSettings.fnRecordsDisplay()==oSettings.fnRecordsTotal()){nFirst.innerHTML=oSettings.oLanguage.sInfo.replace("_START_",oSettings._iDisplayStart+1).replace("_END_",oSettings.fnDisplayEnd()).replace("_TOTAL_",oSettings.fnRecordsDisplay())+oSettings.oLanguage.sInfoPostFix;}else{nFirst.innerHTML=oSettings.oLanguage.sInfo.replace("_START_",oSettings._iDisplayStart+1).replace("_END_",oSettings.fnDisplayEnd()).replace("_TOTAL_",oSettings.fnRecordsDisplay())+" "+oSettings.oLanguage.sInfoFiltered.replace("_MAX_",oSettings.fnRecordsTotal())+oSettings.oLanguage.sInfoPostFix;}}}var n=oSettings.aanFeatures.i;if(n.length>1){var sInfo=nFirst.innerHTML;for(var i=1,iLen=n.length;i';var nLength=document.createElement("div");if(oSettings.sTableId!==""&&typeof oSettings.aanFeatures.l=="undefined"){nLength.setAttribute("id",oSettings.sTableId+"_length");}nLength.className=oSettings.oClasses.sLength;nLength.innerHTML=oSettings.oLanguage.sLengthMenu.replace("_MENU_",sStdMenu);$('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true);$("select",nLength).change(function(e){var iVal=$(this).val();var n=oSettings.aanFeatures.l;for(var i=0,iLen=n.length;ioSettings.aiDisplay.length||oSettings._iDisplayLength==-1){oSettings._iDisplayEnd=oSettings.aiDisplay.length;}else{oSettings._iDisplayEnd=oSettings._iDisplayStart+oSettings._iDisplayLength;}}}function _fnConvertToWidth(sWidth,nParent){if(!sWidth||sWidth===null||sWidth===""){return 0;}if(typeof nParent=="undefined"){nParent=document.getElementsByTagName("body")[0];}var iWidth;var nTmp=document.createElement("div");nTmp.style.width=sWidth;nParent.appendChild(nTmp);iWidth=nTmp.offsetWidth;nParent.removeChild(nTmp);return(iWidth);}function _fnCalculateColumnWidths(oSettings){var iTableWidth=oSettings.nTable.offsetWidth;var iTotalUserIpSize=0;var iTmpWidth;var iVisibleColumns=0;var iColums=oSettings.aoColumns.length;var i;var oHeaders=$("thead:eq(0)>th",oSettings.nTable);for(i=0;i';var sCalcHead="";var sCalcHtml="";for(i=0;i"+oSettings.aoColumns[i].sTitle+"";if(oSettings.aoColumns[i].sWidth!==null){var sWidth="";if(oSettings.aoColumns[i].sWidth!==null){sWidth=' style="width:'+oSettings.aoColumns[i].sWidth+';"';}sCalcHtml+="'+fnGetMaxLenString(oSettings,i)+"";}else{sCalcHtml+=''+fnGetMaxLenString(oSettings,i)+"";}}}sCalcHead+="";sCalcHtml+="";nCalcTmp=$(sTableTmp+sCalcHead+sCalcHtml+"")[0];nCalcTmp.style.width=iTableWidth+"px";nCalcTmp.style.visibility="hidden";nCalcTmp.style.position="absolute";oSettings.nTable.parentNode.appendChild(nCalcTmp);var oNodes=$("tr:eq(1)>td",nCalcTmp);var iIndex;for(i=0;iiMax){iMax=oSettings.aoData[i]._aData[iCol].length;iMaxIndex=i;}}if(iMaxIndex>=0){return oSettings.aoData[iMaxIndex]._aData[iCol];}return"";}function _fnArrayCmp(aArray1,aArray2){if(aArray1.length!=aArray2.length){return 1;}for(var i=0;it<"F"ip>';}}if(typeof oInit.iDisplayStart!="undefined"&&typeof oSettings.iInitDisplayStart=="undefined"){oSettings.iInitDisplayStart=oInit.iDisplayStart;oSettings._iDisplayStart=oInit.iDisplayStart;}if(typeof oInit.bStateSave!="undefined"){oSettings.oFeatures.bStateSave=oInit.bStateSave;_fnLoadState(oSettings,oInit);oSettings.aoDrawCallback.push({fn:_fnSaveState,sName:"state_save"});}if(typeof oInit.aaData!="undefined"){bUsePassedData=true;}if(typeof oInit!="undefined"&&typeof oInit.aoData!="undefined"){oInit.aoColumns=oInit.aoData;}if(typeof oInit.oLanguage!="undefined"){if(typeof oInit.oLanguage.sUrl!="undefined"&&oInit.oLanguage.sUrl!==""){oSettings.oLanguage.sUrl=oInit.oLanguage.sUrl;$.getJSON(oSettings.oLanguage.sUrl,null,function(json){_fnLanguageProcess(oSettings,json,true);});bInitHandedOff=true;}else{_fnLanguageProcess(oSettings,oInit.oLanguage,false);}}}else{oInit={};}if(typeof oInit.asStripClasses=="undefined"){oSettings.asStripClasses.push(oSettings.oClasses.sStripOdd);oSettings.asStripClasses.push(oSettings.oClasses.sStripEven);}var nThead=this.getElementsByTagName("thead");var nThs=nThead.length===0?null:_fnGetUniqueThs(nThead[0]);var bUseCols=typeof oInit.aoColumns!="undefined";for(i=0,iLen=bUseCols?oInit.aoColumns.length:nThs.length;imissing');},authors2html:function(authorData){var authorsStr="";for(var index=0;index0){authorsStr+=", ";}authorsStr+=authorData[index].first+" "+authorData[index].last;}return htmlify(authorsStr);},links:function(entryData){var itemStr="";if(entryData.url&&entryData.url.match(/.*\.pdf/)){itemStr+=' (open access)';}else{if(entryData.url){itemStr+=' (open access)';}}if(entryData.prj){itemStr+=' (open source)';}return itemStr;},doi:function(entryData){var itemStr="";if(entryData.doi){itemStr+=' (doi)';}return itemStr;},comment:function(entryData){var itemStr="";if(entryData.comment){itemStr+=" "+entryData.comment+"";}return itemStr;},pmid:function(entryData){var itemStr="";if(entryData.pmid){itemStr+=' (pmid)';}return itemStr;},bibtex:function(entryData){var itemStr="";itemStr+=' (bib)";return itemStr;},tweet:function(entryData,bib){var itemStr=' ("+entryData.booktitle+", pp. "+entryData.pages+((entryData.address)?", "+entryData.address:"")+".";},article:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.title+". "+entryData.journal+", "+entryData.volume+((entryData.number)?"("+entryData.number+")":"")+", pp. "+entryData.pages+". "+((entryData.address)?entryData.address+".":"")+"";},misc:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.title+". "+((entryData.howpublished)?entryData.howpublished+". ":"")+((entryData.note)?entryData.note+".":"");},mastersthesis:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.title+". "+entryData.type+". "+entryData.organization+", "+entryData.school+".";},techreport:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.title+". "+entryData.institution+". "+entryData.number+". "+entryData.type+".";},book:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.title+", "+entryData.publisher+", "+entryData.year+((entryData.issn)?", ISBN: "+entryData.issn+".":".");},inbook:function(entryData){return this.authors2html(entryData.author)+" ("+entryData.year+"). "+entryData.chapter+" in "+entryData.title+", "+((entryData.editor)?" Edited by "+entryData.editor+", ":"")+entryData.publisher+", pp. "+entryData.pages+""+((entryData.series)?", "+entryData.series+"":"")+((entryData.volume)?", Vol. "+entryData.volume+"":"")+((entryData.issn)?", ISBN: "+entryData.issn+"":"")+".";},importance:{TITLE:9999,misc:0,manual:10,techreport:20,mastersthesis:30,inproceedings:40,incollection:50,proceedings:60,conference:70,article:30,phdthesis:90,inbook:100,book:110,unpublished:120},labels:{article:"Journal",book:"Book",conference:"Talk",inbook:"Book chapter",incollection:"",inproceedings:"Abstract",manual:"Manual",mastersthesis:"Thesis",misc:"Misc",phdthesis:"PhD Thesis",proceedings:"Conference proceeding",techreport:"Technical report",unpublished:"Unpublished"}};bib2html.phdthesis=bib2html.mastersthesis;bib2html.conference=bib2html.inproceedings;var EventHandlers={showbib:function showbib(event){$(this).next(".bibinfo").removeClass("hidden").addClass("open");$("#shutter").show();event.preventDefault();},hidebib:function hidebib(event){$("#shutter").hide();$(".bibinfo.open").removeClass("open").addClass("hidden");event.preventDefault();}};var Bib2HTML=function(data,$pubTable,options){this.options=options;this.$pubTable=$pubTable;this.stats={};this.initialize(data);};var bibproto=Bib2HTML.prototype;bibproto.initialize=function initialize(data){var bibtex=new BibTex();bibtex.content=data;bibtex.parse();var bibentries=[],len=bibtex.data.length;var entryTypes={};jQuery.extend(true,bib2html,this.options.bib2html);for(var index=0;indexitem2)?1:0));};jQuery.fn.dataTableExt.oSort["type-sort-desc"]=function(x,y){var item1=bib2html.importance[entryTypes[x]],item2=bib2html.importance[entryTypes[y]];return((item1item2)?-1:0));};var table=this.$pubTable.dataTable({aaData:bibentries,aaSorting:this.options.sorting,aoColumns:[{sTitle:"Year"},{sTitle:"Type",sType:"type-sort",asSorting:["desc","asc"]},{sTitle:"Publication",bSortable:false}],bPaginate:false});if(this.options.visualization){this.addBarChart();}$("th",this.$pubTable).unbind("click").click(function(e){var $this=$(this),$thElems=$this.parent().find("th"),index=$thElems.index($this);if($this.hasClass("sorting_disabled")){return;}$this.toggleClass("sorting_asc").toggleClass("sorting_desc");if(index===0){table.fnSort([[0,$thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"],[1,$thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"]]);}else{table.fnSort([[1,$thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"],[0,$thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"]]);}});$(".biblink",this.$pubTable).live("click",EventHandlers.showbib);$(".bibclose",this.$pubTable).live("click",EventHandlers.hidebib);};bibproto.updateStats=function updateStats(item){if(!this.stats[item.year]){this.stats[item.year]={count:1,types:{}};this.stats[item.year].types[item.entryType]=1;}else{this.stats[item.year].count+=1;if(this.stats[item.year].types[item.entryType]){this.stats[item.year].types[item.entryType]+=1;}else{this.stats[item.year].types[item.entryType]=1;}}};bibproto.addBarChart=function addBarChart(){var yearstats=[],max=0;$.each(this.stats,function(key,value){max=Math.max(max,value.count);yearstats.push({year:key,count:value.count,item:value,types:value.types});});yearstats.sort(function(a,b){var diff=a.year-b.year;if(!isNaN(diff)){return diff;}else{if(a.yearb.year){return 1;}}}return 0;});var chartIdSelector="#"+this.$pubTable[0].id+"pubchart";var pubHeight=$(chartIdSelector).height()/max-2;var styleStr=chartIdSelector+" .year { width: "+(100/yearstats.length)+"%; }"+chartIdSelector+" .pub { height: "+pubHeight+"px; }";var legendTypes=[];var stats2html=function(item){var types=[],str='
',sum=0;$.each(item.types,function(type,value){types.push(type);sum+=value;});types.sort(function(x,y){return bib2html.importance[y]-bib2html.importance[x];});str+='
';for(var i=0;i
';}}return str+'
'+item.year+"
";};var statsHtml="";yearstats.forEach(function(item){statsHtml+=stats2html(item);});var legendHtml='
';for(var i=0,l=legendTypes.length;i'+bib2html.labels[legend];}legendHtml+="
";$(chartIdSelector).html(statsHtml).after(legendHtml);};return function(bibsrc,bibElemId,opts){var options=$.extend({},{visualization:true,sorting:[[0,"desc"],[1,"desc"]]},opts);var $pubTable=$("#"+bibElemId).addClass("bibtable");if($("#shutter").size()===0){$pubTable.before('');$("#shutter").click(EventHandlers.hidebib);}if(options.visualization){$pubTable.before('
');}var $bibSrc=$(bibsrc);if($bibSrc.length){new Bib2HTML($bibSrc.html(),$pubTable,options);$bibSrc.hide();}else{var callbackHandler=function(data){new Bib2HTML(data,$pubTable,options);};$.get(bibsrc,callbackHandler,"text");}};})(jQuery); \ No newline at end of file diff --git a/docs/javascripts/bib-list.js b/docs/javascripts/bib-list.js new file mode 100644 index 0000000..63b87ef --- /dev/null +++ b/docs/javascripts/bib-list.js @@ -0,0 +1,2893 @@ +/*!* + * Javascript BibTex Parser v0.1 + * Copyright (c) 2008 Simon Fraser University + * @author Steve Hannah + * + * + * License: + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * + * Credits: + * + * This library is a port of the PEAR Structures_BibTex parser written + * in PHP (http://pear.php.net/package/Structures_BibTex). + * + * In order to make porting the parser into javascript easier, I have made + * use of many phpjs functions, which are distributed here under the MIT License: + * + * + * More info at: http://kevin.vanzonneveld.net/techblog/category/php2js + * + * php.js is copyright 2008 Kevin van Zonneveld. + * + * Portions copyright Ates Goral (http://magnetiq.com), Legaev Andrey, + * _argos, Jonas Raoni Soares Silva (http://www.jsfromhell.com), + * Webtoolkit.info (http://www.webtoolkit.info/), Carlos R. L. Rodrigues, Ash + * Searle (http://hexmen.com/blog/), Tyler Akins (http://rumkin.com), mdsjack + * (http://www.mdsjack.bo.it), Alexander Ermolaev + * (http://snippets.dzone.com/user/AlexanderErmolaev), Andrea Giammarchi + * (http://webreflection.blogspot.com), Bayron Guevara, Cord, David, Karol + * Kowalski, Leslie Hoare, Lincoln Ramsay, Mick@el, Nick Callen, Peter-Paul + * Koch (http://www.quirksmode.org/js/beat.html), Philippe Baumann, Steve + * Clay, booeyOH + * + * Licensed under the MIT (MIT-LICENSE.txt) license. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL KEVIN VAN ZONNEVELD BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * + * Synopsis: + * ---------- + * + * This class provides the following functionality: + * 1. Parse BibTex into a logical data javascript data structure. + * 2. Output parsed BibTex entries as HTML, RTF, or BibTex. + * + * + * The following usage instructions have been copyed and adapted from the PHP instructions located + * at http://pear.php.net/manual/en/package.structures.structures-bibtex.intro.php + * Introduction + * -------------- + * Overview + * ---------- + * This package provides methods to access information stored in a BibTex + * file. During parsing it is possible to let the data be validated. In + * addition. the creation of BibTex Strings as well as RTF Strings is also + * supported. A few examples + * + * Example 1. Loading a BibTex File and printing the parsed array + * + * + * + * + * Options + * -------- + * Options can be set either in the constructor or with the method + * setOption(). When setting in the constructor the options are given in an + * associative array. The options are: + * + * - stripDelimiter (default: true) Stripping the delimiter surrounding the entries. + * - validate (default: true) Validation while parsing. + * - unwrap (default: false) Unwrapping entries while parsing. + * - wordWrapWidth (default: false) If set to a number higher one + * that the entries are wrapped after that amount of characters. + * - wordWrapBreak (default: \n) String used to break the line (attached to the line). + * - wordWrapCut (default: 0) If set to zero the line will we + * wrapped at the next possible space, if set to one the line will be + * wrapped exactly after the given amount of characters. + * - removeCurlyBraces (default: false) If set to true Curly Braces will be removed. + * + * Example of setting options in the constructor: + * + * Example 2. Setting options in the constructor + * bibtex = new BibTex({'validate':false, 'unwrap':true}); + * + * + * Example of setting options using the method setOption(): + * + * Example 62-3. Setting options using setOption + * bibtex = new BibTex(); + * bibtex.setOption('validate', false); + * bibtex.setOption('unwrap', true); + * + * Stored Data + * ------------ + * The data is stored in the class variable data. This is a a list where + * each entry is a hash table representing one bibtex-entry. The keys of + * the hash table correspond to the keys used in bibtex and the values are + * the corresponding values. Some of these keys are: + * + * - cite - The key used in a LaTeX source to do the citing. + * - entryType - The type of the entry, like techreport, book and so on. + * - author - One or more authors of the entry. This entry is also a + * list with hash tables representing the authors as entries. The + * author has table is explained later. + * - title - Title of the entry. + * + * Author + * ------ + * As described before the authors are stored in a list. Every entry + * representing one author as a has table. The hash table consits of four + * keys: first, von, last and jr. The keys are explained in the following + * list: + * + * - first - The first name of the author. + * - von - Some names have a 'von' part in their name. This is usually a sign of nobleness. + * - last - The last name of the author. + * - jr - Sometimes a author is the son of his father and has the + * same name, then the value would be jr. The same is true for the + * value sen but vice versa. + * + * Adding an entry + * ---------------- + * To add an entry simply create a hash table with the needed keys and + * values and call the method addEntry(). + * Example 4. Adding an entry + * bibtex = new BibTex(); + * var addarray = {}; + * addarray['entryType'] = 'Article'; + * addarray['cite'] = 'art2'; + * addarray['title'] = 'Titel of the Article'; + * addarray['author'] = []; + * addarray['author'][0]['first'] = 'John'; + * addarray['author'][0]['last'] = 'Doe'; + * addarray['author'][1]['first'] = 'Jane'; + * addarray['author'][1]['last'] = 'Doe'; + * bibtex.addEntry(addarray); + */ + +// ------------BEGIN PHP FUNCTIONS -------------------------------------------------------------- // + +// {{{ array +function array( ) { + // #!#!#!#!# array::$descr1 does not contain valid 'array' at line 258 + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array/ + // + version: 805.1716 + // + original by: d3x + // * example 1: array('Kevin', 'van', 'Zonneveld'); + // * returns 1: ['Kevin', 'van', 'Zonneveld']; + + return Array.prototype.slice.call(arguments); +}// }}} + +// {{{ array_key_exists +function array_key_exists ( key, search ) { + // Checks if the given key or index exists in the array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_key_exists/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Felix Geisendoerfer (http://www.debuggable.com/felix) + // * example 1: array_key_exists('kevin', {'kevin': 'van Zonneveld'}); + // * returns 1: true + + // input sanitation + if( !search || (search.constructor !== Array && search.constructor !== Object) ){ + return false; + } + + return key in search; +}// }}}// {{{ array_keys +function array_keys( input, search_value, strict ) { + // Return all the keys of an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_keys/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: array_keys( {firstname: 'Kevin', surname: 'van Zonneveld'} ); + // * returns 1: {0: 'firstname', 1: 'surname'} + + var tmp_arr = new Array(), strict = !!strict, include = true, cnt = 0; + + for ( key in input ){ + include = true; + if ( search_value != undefined ) { + if( strict && input[key] !== search_value ){ + include = false; + } else if( input[key] != search_value ){ + include = false; + } + } + + if( include ) { + tmp_arr[cnt] = key; + cnt++; + } + } + + return tmp_arr; +}// }}} + +// {{{ in_array +function in_array(needle, haystack, strict) { + // Checks if a value exists in an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_in_array/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: in_array('van', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: true + + var found = false, key, strict = !!strict; + + for (key in haystack) { + if ((strict && haystack[key] === needle) || (!strict && haystack[key] == needle)) { + found = true; + break; + } + } + + return found; +}// }}} + +// {{{ sizeof +function sizeof ( mixed_var, mode ) { + // Alias of count() + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_sizeof/ + // + version: 804.1712 + // + original by: Philip Peterson + // - depends on: count + // * example 1: sizeof([[0,0],[0,-4]], 'COUNT_RECURSIVE'); + // * returns 1: 6 + // * example 2: sizeof({'one' : [1,2,3,4,5]}, 'COUNT_RECURSIVE'); + // * returns 2: 6 + + return count( mixed_var, mode ); +}// }}} + +// {{{ count +function count( mixed_var, mode ) { + // Count elements in an array, or properties in an object + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_count/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: _argos + // * example 1: count([[0,0],[0,-4]], 'COUNT_RECURSIVE'); + // * returns 1: 6 + // * example 2: count({'one' : [1,2,3,4,5]}, 'COUNT_RECURSIVE'); + // * returns 2: 6 + + var key, cnt = 0; + + if( mode == 'COUNT_RECURSIVE' ) mode = 1; + if( mode != 1 ) mode = 0; + + for (key in mixed_var){ + cnt++; + if( mode==1 && mixed_var[key] && (mixed_var[key].constructor === Array || mixed_var[key].constructor === Object) ){ + cnt += count(mixed_var[key], 1); + } + } + + return cnt; +}// }}} + +// {{{ explode +function explode( delimiter, string, limit ) { + // Split a string by string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_explode/ + // + version: 805.1715 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: kenneth + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: d3x + // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: explode(' ', 'Kevin van Zonneveld'); + // * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'} + // * example 2: explode('=', 'a=bc=d', 2); + // * returns 2: ['a', 'bc=d'] + + var emptyArray = { 0: '' }; + + // third argument is not required + if ( arguments.length < 2 + || typeof arguments[0] == 'undefined' + || typeof arguments[1] == 'undefined' ) + { + return null; + } + + if ( delimiter === '' + || delimiter === false + || delimiter === null ) + { + return false; + } + + if ( typeof delimiter == 'function' + || typeof delimiter == 'object' + || typeof string == 'function' + || typeof string == 'object' ) + { + return emptyArray; + } + + if ( delimiter === true ) { + delimiter = '1'; + } + + if (!limit) { + return string.toString().split(delimiter.toString()); + } else { + // support for limit argument + var splitted = string.toString().split(delimiter.toString()); + var partA = splitted.splice(0, limit - 1); + var partB = splitted.join(delimiter.toString()); + partA.push(partB); + return partA; + } +}// }}} + +// {{{ implode +function implode( glue, pieces ) { + // Join array elements with a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_implode/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: _argos + // * example 1: implode(' ', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: 'Kevin van Zonneveld' + + return ( ( pieces instanceof Array ) ? pieces.join ( glue ) : pieces ); +}// }}} + +// {{{ join +function join( glue, pieces ) { + // Alias of implode() + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_join/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: implode + // * example 1: join(' ', ['Kevin', 'van', 'Zonneveld']); + // * returns 1: 'Kevin van Zonneveld' + + return implode( glue, pieces ); +}// }}} + +// {{{ split +function split( delimiter, string ) { + // Split string into array by regular expression + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_split/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // - depends on: explode + // * example 1: split(' ', 'Kevin van Zonneveld'); + // * returns 1: {0: 'Kevin', 1: 'van', 2: 'Zonneveld'} + + return explode( delimiter, string ); +}// }}} + +// {{{ str_replace +function str_replace(search, replace, subject) { + // Replace all occurrences of the search string with the replacement string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_str_replace/ + // + version: 805.3114 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Gabriel Paderni + // + improved by: Philip Peterson + // + improved by: Simon Willison (http://simonwillison.net) + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // - depends on: is_array + // * example 1: str_replace(' ', '.', 'Kevin van Zonneveld'); + // * returns 1: 'Kevin.van.Zonneveld' + // * example 2: str_replace(['{name}', 'l'], ['hello', 'm'], '{name}, lars'); + // * returns 2: 'hemmo, mars' + + var f = search, r = replace, s = subject; + var ra = is_array(r), sa = is_array(s), f = [].concat(f), r = [].concat(r), i = (s = [].concat(s)).length; + + while (j = 0, i--) { + while (s[i] = s[i].split(f[j]).join(ra ? r[j] || "" : r[0]), ++j in f){}; + }; + + return sa ? s : s[0]; +}// }}} + +// {{{ strlen +function strlen( string ){ + // Get string length + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strlen/ + // + version: 805.1616 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Sakimori + // * example 1: strlen('Kevin van Zonneveld'); + // * returns 1: 19 + + return ("" + string).length; +}// }}} + +// {{{ strpos +function strpos( haystack, needle, offset){ + // Find position of first occurrence of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strpos/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strpos('Kevin van Zonneveld', 'e', 5); + // * returns 1: 14 + + var i = haystack.indexOf( needle, offset ); // returns -1 + return i >= 0 ? i : false; +}// }}} + +// {{{ strrpos +function strrpos( haystack, needle, offset){ + // Find position of last occurrence of a char in a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strrpos/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strrpos('Kevin van Zonneveld', 'e'); + // * returns 1: 16 + + var i = haystack.lastIndexOf( needle, offset ); // returns -1 + return i >= 0 ? i : false; +}// }}} + +// {{{ strtolower +function strtolower( str ) { + // Make a string lowercase + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strtolower/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strtolower('Kevin van Zonneveld'); + // * returns 1: 'kevin van zonneveld' + + return str.toLowerCase(); +}// }}} + +// {{{ strtoupper +function strtoupper( str ) { + // Make a string uppercase + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_strtoupper/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: strtoupper('Kevin van Zonneveld'); + // * returns 1: 'KEVIN VAN ZONNEVELD' + + return str.toUpperCase(); +}// }}} + +// {{{ substr +function substr( f_string, f_start, f_length ) { + // Return part of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_substr/ + // + version: 804.1712 + // + original by: Martijn Wieringa + // * example 1: substr('abcdef', 0, -1); + // * returns 1: 'abcde' + + if(f_start < 0) { + f_start += f_string.length; + } + + if(f_length == undefined) { + f_length = f_string.length; + } else if(f_length < 0){ + f_length += f_string.length; + } else { + f_length += f_start; + } + + if(f_length < f_start) { + f_length = f_start; + } + + return f_string.substring(f_start, f_length); +}// }}} + +// {{{ trim +function trim( str, charlist ) { + // Strip whitespace (or other characters) from the beginning and end of a string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_trim/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: mdsjack (http://www.mdsjack.bo.it) + // + improved by: Alexander Ermolaev (http://snippets.dzone.com/user/AlexanderErmolaev) + // + input by: Erkekjetter + // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + input by: DxGx + // + improved by: Steven Levithan (http://blog.stevenlevithan.com) + // * example 1: trim(' Kevin van Zonneveld '); + // * returns 1: 'Kevin van Zonneveld' + // * example 2: trim('Hello World', 'Hdle'); + // * returns 2: 'o Wor' + if (!str) { return ''; } + var whitespace; + + if(!charlist){ + whitespace = ' \n\r\t\f\x0b\xa0\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u200b\u2028\u2029\u3000'; + } else{ + whitespace = charlist.replace(/([\[\]\(\)\.\?\/\*\{\}\+\$\^\:])/g, '\$1'); + } + + for (var i = 0; i < str.length; i++) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(i); + break; + } + } + for (i = str.length - 1; i >= 0; i--) { + if (whitespace.indexOf(str.charAt(i)) === -1) { + str = str.substring(0, i + 1); + break; + } + } + return whitespace.indexOf(str.charAt(0)) === -1 ? str : ''; +}// }}} + + +// {{{ wordwrap +function wordwrap( str, int_width, str_break, cut ) { + // Wraps a string to a given number of characters + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_wordwrap/ + // + version: 804.1715 + // + original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // + improved by: Nick Callen + // + revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com) + // * example 1: wordwrap('Kevin van Zonneveld', 6, '|', true); + // * returns 1: 'Kevin |van |Zonnev|eld' + + var m = int_width, b = str_break, c = cut; + var i, j, l, s, r; + + if(m < 1) { + return str; + } + for(i = -1, l = (r = str.split("\n")).length; ++i < l; r[i] += s) { + for(s = r[i], r[i] = ""; s.length > m; r[i] += s.slice(0, j) + ((s = s.slice(j)).length ? b : "")){ + j = c == 2 || (j = s.slice(0, m + 1).match(/\S*(\s)?$/))[1] ? m : j.input.length - j[0].length || c == 1 && m || j.input.length + (j = s.slice(m).match(/^\S*/)).input.length; + } + } + + return r.join("\n"); +}// }}} + +// {{{ is_string +function is_string( mixed_var ){ + // Find whether the type of a variable is string + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_string/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: is_string('23'); + // * returns 1: true + // * example 2: is_string(23.5); + // * returns 2: false + + return (typeof( mixed_var ) == 'string'); +}// }}} + + +// {{{ ord +function ord( string ) { + // Return ASCII value of character + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_ord/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: ord('K'); + // * returns 1: 75 + + return string.charCodeAt(0); +}// }}} + +// {{{ array_unique +function array_unique( array ) { + // Removes duplicate values from an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_array_unique/ + // + version: 805.211 + // + original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com) + // + input by: duncan + // + bufixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // * example 1: array_unique(['Kevin','Kevin','van','Zonneveld']); + // * returns 1: ['Kevin','van','Zonneveld'] + + var p, i, j, tmp_arr = array; + for(i = tmp_arr.length; i;){ + for(p = --i; p > 0;){ + if(tmp_arr[i] === tmp_arr[--p]){ + for(j = p; --p && tmp_arr[i] === tmp_arr[p];); + i -= tmp_arr.splice(p + 1, j - p).length; + } + } + } + + return tmp_arr; +}// }}} + +// {{{ print_r +function print_r( array, return_val ) { + // Prints human-readable information about a variable + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_print_r/ + // + version: 805.2023 + // + original by: Michael White (http://crestidg.com) + // + improved by: Ben Bryan + // * example 1: print_r(1, true); + // * returns 1: 1 + + var output = "", pad_char = " ", pad_val = 4; + + var formatArray = function (obj, cur_depth, pad_val, pad_char) { + if (cur_depth > 0) { + cur_depth++; + } + + var base_pad = repeat_char(pad_val*cur_depth, pad_char); + var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char); + var str = ""; + + if (obj instanceof Array || obj instanceof Object) { + str += "Array\n" + base_pad + "(\n"; + for (var key in obj) { + if (obj[key] instanceof Array || obj[key] instanceof Object) { + str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char); + } else { + str += thick_pad + "["+key+"] => " + obj[key] + "\n"; + } + } + str += base_pad + ")\n"; + } else { + str = obj.toString(); + } + + return str; + }; + + var repeat_char = function (len, pad_char) { + var str = ""; + for(var i=0; i < len; i++) { + str += pad_char; + }; + return str; + }; + output = formatArray(array, 0, pad_val, pad_char); + + if (return_val !== true) { + document.write("
" + output + "
"); + return true; + } else { + return output; + } +}// }}} +// {{{ is_array +function is_array( mixed_var ) { + // Finds whether a variable is an array + // + // + discuss at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/ + // + version: 804.1712 + // + original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) + // + improved by: Legaev Andrey + // + bugfixed by: Cord + // * example 1: is_array(['Kevin', 'van', 'Zonneveld']); + // * returns 1: true + // * example 2: is_array('Kevin van Zonneveld'); + // * returns 2: false + + return ( mixed_var instanceof Array ); +}// }}} + +//------------END PHP FUNCTIONS -------------------------------------------------------------- // + +/** + * BibTex + * + * A class which provides common methods to access and + * create Strings in BibTex format+ + * Example 1: Parsing a BibTex File and returning the number of entries + * + * bibtex = new BibTex(); + * bibtex.content = '....'; + * + * bibtex.parse(); + * print "There are "+bibtex.amount()+" entries"; + * + * Example 2: Parsing a BibTex File and getting all Titles + * + * bibtex = new BibTex(); + * bibtex.content="..."; + * bibtex.parse(); + * for (var i in bibtex.data) { + * alert( bibtex.data[i]['title']+"
"); + * } + *
+ * Example 3: Adding an entry and printing it in BibTex Format + * + * bibtex = new BibTex(); + * addarray = {} + * addarray['entryType'] = 'Article'; + * addarray['cite'] = 'art2'; + * addarray['title'] = 'Titel2'; + * addarray['author'] = []; + * addarray['author'][0]['first'] = 'John'; + * addarray['author'][0]['last'] = 'Doe'; + * addarray['author'][1]['first'] = 'Jane'; + * addarray['author'][1]['last'] = 'Doe'; + * bibtex.addEntry(addarray); + * alert( nl2br(bibtex.bibTex())); + * + * + * @category Structures + * @package BibTex + * @author Steve Hannah + * @adapted-from Structures_BibTex by Elmar Pitschke + * @copyright 2008 Simon Fraser University + * @license http://www.gnu.org/licenses/lgpl.html + * @version Release: 0.1 + * @link http://webgroup.fas.sfu.ca/projects/JSBibTexParser + */ +function BibTex(options) +{ + + if ( typeof options == 'undefined' ) options = {}; + /** + * Array with the BibTex Data + * + * @access public + * @var array + */ + this.data; + /** + * String with the BibTex content + * + * @access public + * @var string + */ + this.content; + /** + * Array with possible Delimiters for the entries + * + * @access private + * @var array + */ + this._delimiters; + /** + * Array to store warnings + * + * @access public + * @var array + */ + this.warnings; + /** + * Run-time configuration options + * + * @access private + * @var array + */ + this._options; + /** + * RTF Format String + * + * @access public + * @var string + */ + this.rtfstring; + /** + * HTML Format String + * + * @access public + * @var string + */ + this.htmlstring; + /** + * Array with the "allowed" entry types + * + * @access public + * @var array + */ + this.allowedEntryTypes; + /** + * Author Format Strings + * + * @access public + * @var string + */ + this.authorstring; + + this._delimiters = {'"':'"', + '{':'}'}; + this.data = []; + this.content = ''; + //this._stripDelimiter = stripDel; + //this._validate = val; + this.warnings = []; + this._options = { + 'stripDelimiter' : true, + 'validate' : true, + 'unwrap' : false, + 'wordWrapWidth' : false, + 'wordWrapBreak' : "\n", + 'wordWrapCut' : 0, + 'removeCurlyBraces' : false, + 'extractAuthors' : true + }; + for (option in options) { + test = this.setOption(option, options[option]); + if (this.isError(test)) { + //Currently nothing is done here, but it could for example raise an warning + } + } + this.rtfstring = 'AUTHORS, "{\b TITLE}", {\i JOURNAL}, YEAR'; + this.htmlstring = 'AUTHORS, "TITLE", JOURNAL, YEAR
'; + this.allowedEntryTypes = array( + 'article', + 'book', + 'booklet', + 'confernce', + 'inbook', + 'incollection', + 'inproceedings', + 'manual', + 'masterthesis', + 'misc', + 'phdthesis', + 'proceedings', + 'techreport', + 'unpublished' + ); + this.authorstring = 'VON LAST, JR, FIRST'; + +} + + +BibTex.prototype = { + + /** + * Constructor + * + * @access public + * @return void + */ + + + /** + * Sets run-time configuration options + * + * @access public + * @param string option option name + * @param mixed value value for the option + * @return mixed true on success PEAR_Error on failure + */ + setOption : function(option, value) + { + ret = true; + if (array_key_exists(option, this._options)) { + this._options[option] = value; + } else { + ret = this.raiseError('Unknown option '+option); + } + return ret; + }, + + /** + * Reads a give BibTex File + * + * @access public + * @param string filename Name of the file + * @return mixed true on success PEAR_Error on failure + * + function loadFile(filename) + { + if (file_exists(filename)) { + if ((this.content = @file_get_contents(filename)) === false) { + return PEAR::raiseError('Could not open file '+filename); + } else { + this._pos = 0; + this._oldpos = 0; + return true; + } + } else { + return PEAR::raiseError('Could not find file '+filename); + } + } + */ + /** + * Parses what is stored in content and clears the content if the parsing is successfull+ + * + * @access public + * @return boolean true on success and PEAR_Error if there was a problem + */ + parse: function() + { + //alert("starting to parse"); + //The amount of opening braces is compared to the amount of closing braces + //Braces inside comments are ignored + this.warnings = []; + this.data = []; + var valid = true; + var open = 0; + var entry = false; + var charv = ''; + var lastchar = ''; + var buffer = ''; + for (var i = 0; i < strlen(this.content); i++) { + charv = substr(this.content, i, 1); + if ((0 != open) && ('@' == charv)) { + if (!this._checkAt(buffer)) { + this._generateWarning('WARNING_MISSING_END_BRACE', '', buffer); + //To correct the data we need to insert a closing brace + charv = '}'; + i--; + } + } + if ((0 == open) && ('@' == charv)) { //The beginning of an entry + entry = true; + } else if (entry && ('{' == charv) && ('\\' != lastchar)) { //Inside an entry and non quoted brace is opening + open++; + } else if (entry && ('}' == charv) && ('\\' != lastchar)) { //Inside an entry and non quoted brace is closing + open--; + if (open < 0) { //More are closed than opened + valid = false; + } + if (0 == open) { //End of entry + entry = false; + var entrydata = this._parseEntry(buffer); + if (!entrydata) { + /** + * This is not yet used+ + * We are here if the Entry is either not correct or not supported+ + * But this should already generate a warning+ + * Therefore it should not be necessary to do anything here + */ + } else { + this.data[this.data.length] = entrydata; + } + buffer = ''; + } + } + if (entry) { //Inside entry + buffer += charv; + } + lastchar = charv; + } + //If open is one it may be possible that the last ending brace is missing + if (1 == open) { + entrydata = this._parseEntry(buffer); + if (!entrydata) { + valid = false; + } else { + this.data[this.data.length] = entrydata; + buffer = ''; + open = 0; + } + } + //At this point the open should be zero + if (0 != open) { + valid = false; + } + //Are there Multiple entries with the same cite? + if (this._options['validate']) { + cites = []; + for (var i=0; i< this.data.length; i++ ) { + cites[cites.length] = this.data[i]['cite']; + } + unique = array_unique(cites); + if (cites.length != sizeof(unique)) { //Some values have not been unique! + notuniques = []; + for (var i = 0; i < cites.length; i++) { + if ('' == unique[i]) { + notuniques[notuniques.length] = cites[i]; + } + } + this._generateWarning('WARNING_MULTIPLE_ENTRIES', implode(',',notuniques)); + } + } + //alert("finished parsing"); + if (valid) { + this.content = ''; + return true; + } else { + return this.raiseError('Unbalanced parenthesis'); + } + }, + + /** + * Extracting the data of one content + * + * The parse function splits the content into its entries+ + * Then every entry is parsed by this function+ + * It parses the entry backwards+ + * First the last '=' is searched and the value extracted from that+ + * A copy is made of the entry if warnings should be generated+ This takes quite + * some memory but it is needed to get good warnings+ If nor warnings are generated + * then you don have to worry about memory+ + * Then the last ',' is searched and the field extracted from that+ + * Again the entry is shortened+ + * Finally after all field:value pairs the cite and type is extraced and the + * authors are splitted+ + * If there is a problem false is returned+ + * + * @access private + * @param string entry The entry + * @return array The representation of the entry or false if there is a problem + */ + '_parseEntry': function(entry) + { + var entrycopy = ''; + if (this._options['validate']) { + entrycopy = entry; //We need a copy for printing the warnings + } + var ret = {}; + if ('@string' == strtolower(substr(entry, 0, 7))) { + //String are not yet supported! + if (this._options['validate']) { + this._generateWarning('STRING_ENTRY_NOT_YET_SUPPORTED', '', entry+'}'); + } + } else if ('@preamble' == strtolower(substr(entry, 0, 9))) { + //Preamble not yet supported! + if (this._options['validate']) { + this._generateWarning('PREAMBLE_ENTRY_NOT_YET_SUPPORTED', '', entry+'}'); + } + } else { + //Parsing all fields + while (strrpos(entry,'=') !== false) { + position = strrpos(entry, '='); + //Checking that the equal sign is not quoted or is not inside a equation (For example in an abstract) + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + if (proceed) { + proceed = this._checkEqualSign(entry, position); + } + while (!proceed) { + substring = substr(entry, 0, position); + position = strrpos(substring,'='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + if (proceed) { + proceed = this._checkEqualSign(entry, position); + } + } + + value = trim(substr(entry, position+1)); + entry = substr(entry, 0, position); + + if (',' == substr(value, strlen(value)-1, 1)) { + value = substr(value, 0, -1); + } + if (this._options['validate']) { + this._validateValue(value, entrycopy); + } + if (this._options['stripDelimiter']) { + value = this._stripDelimiter(value); + } + if (this._options['unwrap']) { + value = this._unwrap(value); + } + if (this._options['removeCurlyBraces']) { + value = this._removeCurlyBraces(value); + } + position = strrpos(entry, ','); + field = strtolower(trim(substr(entry, position+1))); + ret[field] = value; + entry = substr(entry, 0, position); + } + //Parsing cite and entry type + var arr = entry.split('{'); + ret['cite'] = trim(arr[1]); + ret['entryType'] = strtolower(trim(arr[0])); + //alert(array_keys(ret)); + if ('@' == ret['entryType'].substring(0,1)) { + ret['entryType'] = substr(ret['entryType'], 1); + } + if (this._options['validate']) { + if (!this._checkAllowedEntryType(ret['entryType'])) { + this._generateWarning('WARNING_NOT_ALLOWED_ENTRY_TYPE', ret['entryType'], entry+'}'); + } + } + //Handling the authors + if (in_array('author', array_keys(ret)) && this._options['extractAuthors']) { + ret['author'] = this._extractAuthors(ret['author']); + } + } + return ret; + }, + + /** + * Checking whether the position of the '=' is correct + * + * Sometimes there is a problem if a '=' is used inside an entry (for example abstract)+ + * This method checks if the '=' is outside braces then the '=' is correct and true is returned+ + * If the '=' is inside braces it contains to a equation and therefore false is returned+ + * + * @access private + * @param string entry The text of the whole remaining entry + * @param int the current used place of the '=' + * @return bool true if the '=' is correct, false if it contains to an equation + */ + '_checkEqualSign': function(entry, position) + { + var ret = true; + //This is getting tricky + //We check the string backwards until the position and count the closing an opening braces + //If we reach the position the amount of opening and closing braces should be equal + var length = strlen(entry); + var open = 0; + for (var i = length-1; i >= position; i--) { + precedingchar = substr(entry, i-1, 1); + charv = substr(entry, i, 1); + if (('{' == charv) && ('\\' != precedingchar)) { + open++; + } + if (('}' == charv) && ('\\' != precedingchar)) { + open--; + } + } + if (0 != open) { + ret = false; + } + //There is still the posibility that the entry is delimited by double quotes+ + //Then it is possible that the braces are equal even if the '=' is in an equation+ + if (ret) { + entrycopy = trim(entry); + lastchar = substr(entrycopy,strlen(entrycopy)-1,1); + if (',' == lastchar) { + lastchar = substr(entrycopy, strlen(entrycopy)-2, 1); + } + if ('"' == lastchar) { + //The return value is set to false + //If we find the closing " before the '=' it is set to true again+ + //Remember we begin to search the entry backwards so the " has to show up twice - ending and beginning delimiter + ret = false; + found = 0; + for (var i = length; i >= position; i--) { + precedingchar = substr(entry, i-1, 1); + charv = substr(entry, i, 1); + if (('"' == charv) && ('\\' != precedingchar)) { + found++; + } + if (2 == found) { + ret = true; + break; + } + } + } + } + return ret; + }, + + /** + * Checking if the entry type is allowed + * + * @access private + * @param string entry The entry to check + * @return bool true if allowed, false otherwise + */ + '_checkAllowedEntryType': function(entry) + { + return in_array(entry, this.allowedEntryTypes); + }, + + /** + * Checking whether an at is outside an entry + * + * Sometimes an entry misses an entry brace+ Then the at of the next entry seems to be + * inside an entry+ This is checked here+ When it is most likely that the at is an opening + * at of the next entry this method returns true+ + * + * @access private + * @param string entry The text of the entry until the at + * @return bool true if the at is correct, false if the at is likely to begin the next entry+ + */ + '_checkAt': function(entry) + { + var ret = false; + var opening = array_keys(this._delimiters); + var closing = array_values(this._delimiters); + //Getting the value (at is only allowd in values) + if (strrpos(entry,'=') !== false) { + position = strrpos(entry, '='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + while (!proceed) { + substring = substr(entry, 0, position); + position = strrpos(substring,'='); + proceed = true; + if (substr(entry, position-1, 1) == '\\') { + proceed = false; + } + } + value = trim(substr(entry, position+1)); + open = 0; + charv = ''; + lastchar = ''; + for (var i = 0; i < strlen(value); i++) { + charv = substr(this.content, i, 1); + if (in_array(charv, opening) && ('\\' != lastchar)) { + open++; + } else if (in_array(charv, closing) && ('\\' != lastchar)) { + open--; + } + lastchar = charv; + } + //if open is grater zero were are inside an entry + if (open>0) { + ret = true; + } + } + return ret; + }, + + /** + * Stripping Delimiter + * + * @access private + * @param string entry The entry where the Delimiter should be stripped from + * @return string Stripped entry + */ + '_stripDelimiter': function(entry) + { + var beginningdels = array_keys(this._delimiters); + var ength = strlen(entry); + var firstchar = substr(entry, 0, 1); + var lastchar = substr(entry, -1, 1); + while (in_array(firstchar, beginningdels)) { //The first character is an opening delimiter + if (lastchar == this._delimiters[firstchar]) { //Matches to closing Delimiter + entry = substr(entry, 1, -1); + } else { + break; + } + firstchar = substr(entry, 0, 1); + lastchar = substr(entry, -1, 1); + } + return entry; + }, + + /** + * Unwrapping entry + * + * @access private + * @param string entry The entry to unwrap + * @return string unwrapped entry + */ + '_unwrap': function(entry) + { + entry = entry.replace(/\s+/, ' '); + return trim(entry); + }, + + /** + * Wordwrap an entry + * + * @access private + * @param string entry The entry to wrap + * @return string wrapped entry + */ + '_wordwrap': function(entry) + { + if ( (''!=entry) && (is_string(entry)) ) { + entry = wordwrap(entry, this._options['wordWrapWidth'], this._options['wordWrapBreak'], this._options['wordWrapCut']); + } + return entry; + }, + + /** + * Extracting the authors + * + * @access private + * @param string entry The entry with the authors + * @return array the extracted authors + */ + '_extractAuthors': function(entry) { + entry = this._unwrap(entry); + var authorarray = entry.split(' and '); + for (var i = 0; i < authorarray.length; i++) { + var author = trim(authorarray[i]); + /*The first version of how an author could be written (First von Last) + has no commas in it*/ + var first = ''; + var von = ''; + var last = ''; + var jr = ''; + if (strpos(author, ',') === false) { + var tmparray = author.split(' |~'); + var size = tmparray.length; + if (1 == size) { //There is only a last + last = tmparray[0]; + } else if (2 == size) { //There is a first and a last + first = tmparray[0]; + last = tmparray[1]; + } else { + var invon = false; + var inlast = false; + for (var j=0; j<(size-1); j++) { + if (inlast) { + last += ' '+tmparray[j]; + } else if (invon) { + casev = this._determineCase(tmparray[j]); + if (this.isError(casev)) { + // IGNORE? + } else if ((0 == casev) || (-1 == casev)) { //Change from von to last + //You only change when there is no more lower case there + islast = true; + for (var k=(j+1); k<(size-1); k++) { + futurecase = this._determineCase(tmparray[k]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == futurecase) { + islast = false; + } + } + if (islast) { + inlast = true; + if (-1 == casev) { //Caseless belongs to the last + last += ' '+tmparray[j]; + } else { + von += ' '+tmparray[j]; + } + } else { + von += ' '+tmparray[j]; + } + } else { + von += ' '+tmparray[j]; + } + } else { + var casev = this._determineCase(tmparray[j]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == casev) { //Change from first to von + invon = true; + von += ' '+tmparray[j]; + } else { + first += ' '+tmparray[j]; + } + } + } + //The last entry is always the last! + last += ' '+tmparray[size-1]; + } + } else { //Version 2 and 3 + var tmparray = []; + tmparray = explode(',', author); + //The first entry must contain von and last + vonlastarray = []; + vonlastarray = explode(' ', tmparray[0]); + size = sizeof(vonlastarray); + if (1==size) { //Only one entry.got to be the last + last = vonlastarray[0]; + } else { + inlast = false; + for (var j=0; j<(size-1); j++) { + if (inlast) { + last += ' '+vonlastarray[j]; + } else { + if (0 != (this._determineCase(vonlastarray[j]))) { //Change from von to last + islast = true; + for (var k=(j+1); k<(size-1); k++) { + this._determineCase(vonlastarray[k]); + casev = this._determineCase(vonlastarray[k]); + if (this.isError(casev)) { + // IGNORE? + } else if (0 == casev) { + islast = false; + } + } + if (islast) { + inlast = true; + last += ' '+vonlastarray[j]; + } else { + von += ' '+vonlastarray[j]; + } + } else { + von += ' '+vonlastarray[j]; + } + } + } + last += ' '+vonlastarray[size-1]; + } + //Now we check if it is version three (three entries in the array (two commas) + if (3==tmparray.length) { + jr = tmparray[1]; + } + //Everything in the last entry is first + first = tmparray[tmparray.length-1]; + } + authorarray[i] = {'first':trim(first), 'von':trim(von), 'last':trim(last), 'jr':trim(jr)}; + } + return authorarray; + }, + + /** + * Case Determination according to the needs of BibTex + * + * To parse the Author(s) correctly a determination is needed + * to get the Case of a word+ There are three possible values: + * - Upper Case (return value 1) + * - Lower Case (return value 0) + * - Caseless (return value -1) + * + * @access private + * @param string word + * @return int The Case or PEAR_Error if there was a problem + */ + '_determineCase': function(word) { + var ret = -1; + var trimmedword = trim (word); + /*We need this variable+ Without the next of would not work + (trim changes the variable automatically to a string!)*/ + if (is_string(word) && (strlen(trimmedword) > 0)) { + var i = 0; + var found = false; + var openbrace = 0; + while (!found && (i <= strlen(word))) { + var letter = substr(trimmedword, i, 1); + var ordv = ord(letter); + if (ordv == 123) { //Open brace + openbrace++; + } + if (ordv == 125) { //Closing brace + openbrace--; + } + if ((ordv>=65) && (ordv<=90) && (0==openbrace)) { //The first character is uppercase + ret = 1; + found = true; + } else if ( (ordv>=97) && (ordv<=122) && (0==openbrace) ) { //The first character is lowercase + ret = 0; + found = true; + } else { //Not yet found + i++; + } + } + } else { + ret = this.raiseError('Could not determine case on word: '+word); + } + return ret; + }, + + + 'isError': function(obj){ + return ( typeof(obj) == 'Object' && obj.isError == 1 ); + + }, + + /** + * Validation of a value + * + * There may be several problems with the value of a field+ + * These problems exist but do not break the parsing+ + * If a problem is detected a warning is appended to the array warnings+ + * + * @access private + * @param string entry The entry aka one line which which should be validated + * @param string wholeentry The whole BibTex Entry which the one line is part of + * @return void + */ + '_validateValue': function(entry, wholeentry) + { + //There is no @ allowed if the entry is enclosed by braces + if ( entry.match(/^{.*@.*}/)) { + this._generateWarning('WARNING_AT_IN_BRACES', entry, wholeentry); + } + //No escaped " allowed if the entry is enclosed by double quotes + if (entry.match(/^\".*\\".*\"/)) { + this._generateWarning('WARNING_ESCAPED_DOUBLE_QUOTE_INSIDE_DOUBLE_QUOTES', entry, wholeentry); + } + //Amount of Braces is not correct + var open = 0; + var lastchar = ''; + var charv = ''; + for (var i = 0; i < strlen(entry); i++) { + charv = substr(entry, i, 1); + if (('{' == charv) && ('\\' != lastchar)) { + open++; + } + if (('}' == charv) && ('\\' != lastchar)) { + open--; + } + lastchar = charv; + } + if (0 != open) { + this._generateWarning('WARNING_UNBALANCED_AMOUNT_OF_BRACES', entry, wholeentry); + } + }, + + /** + * Remove curly braces from entry + * + * @access private + * @param string value The value in which curly braces to be removed + * @param string Value with removed curly braces + */ + '_removeCurlyBraces': function(value) + { + //First we save the delimiters + var beginningdels = array_keys(this._delimiters); + var firstchar = substr(value, 0, 1); + var lastchar = substr(value, -1, 1); + var begin = ''; + var end = ''; + while (in_array(firstchar, beginningdels)) { //The first character is an opening delimiter + if (lastchar == this._delimiters[firstchar]) { //Matches to closing Delimiter + begin += firstchar; + end += lastchar; + value = substr(value, 1, -1); + } else { + break; + } + firstchar = substr(value, 0, 1); + lastchar = substr(value, -1, 1); + } + //Now we get rid of the curly braces + var pattern = '/([^\\\\])\{(+*?[^\\\\])\}/'; + var replacement = '12'; + value = value.replace(/([^\\\\])\{(.*?[^\\\\])\}/, replacement); + //Reattach delimiters + value = begin+value+end; + return value; + }, + + /** + * Generates a warning + * + * @access private + * @param string type The type of the warning + * @param string entry The line of the entry where the warning occurred + * @param string wholeentry OPTIONAL The whole entry where the warning occurred + */ + '_generateWarning': function(type, entry, wholeentry) + { + if ( typeof wholeentry == 'undefined' ) wholeentry = ''; + var warning = {}; + warning['warning'] = type; + warning['entry'] = entry; + warning['wholeentry'] = wholeentry; + this.warnings[this.warnings.length] = warning; + }, + + /** + * Cleares all warnings + * + * @access public + */ + 'clearWarnings': function() + { + this.warnings = array(); + }, + + /** + * Is there a warning? + * + * @access public + * @return true if there is, false otherwise + */ + 'hasWarning': function() + { + if (sizeof(this.warnings)>0) return true; + else return false; + }, + + /** + * Returns the amount of available BibTex entries + * + * @access public + * @return int The amount of available BibTex entries + */ + 'amount': function() + { + return sizeof(this.data); + }, + /** + * Returns the author formatted + * + * The Author is formatted as setted in the authorstring + * + * @access private + * @param array array Author array + * @return string the formatted author string + */ + '_formatAuthor': function(array) + { + if (!array_key_exists('von', array)) { + array['von'] = ''; + } else { + array['von'] = trim(array['von']); + } + if (!array_key_exists('last', array)) { + array['last'] = ''; + } else { + array['last'] = trim(array['last']); + } + if (!array_key_exists('jr', array)) { + array['jr'] = ''; + } else { + array['jr'] = trim(array['jr']); + } + if (!array_key_exists('first', array)) { + array['first'] = ''; + } else { + array['first'] = trim(array['first']); + } + ret = this.authorstring; + ret = str_replace("VON", array['von'], ret); + ret = str_replace("LAST", array['last'], ret); + ret = str_replace("JR", array['jr'], ret); + ret = str_replace("FIRST", array['first'], ret); + return trim(ret); + }, + + /** + * Converts the stored BibTex entries to a BibTex String + * + * In the field list, the author is the last field+ + * + * @access public + * @return string The BibTex string + */ + 'bibTex': function() + { + var bibtex = ''; + for (var i=0 ; i0) { + val = this._wordWrap(val); + } + if (!in_array(key, array('cite','entryType','author'))) { + bibtex += "\t"+key+' = {'+val+"},\n"; + } + } + //Author + if (array_key_exists('author', entry)) { + if (this._options['extractAuthors']) { + tmparray = []; //In this array the authors are saved and the joind with an and + for (j in entry['author']) { + var authorentry = entry['author'][j]; + tmparray[tmparray.length] = this._formatAuthor(authorentry); + } + author = join(' and ', tmparray); + } else { + author = entry['author']; + } + } else { + author = ''; + } + bibtex += "\tauthor = {"+author+"}\n"; + bibtex+="}\n\n"; + } + return bibtex; + }, + + /** + * Adds a new BibTex entry to the data + * + * @access public + * @param array newentry The new data to add + * @return void + */ + 'addEntry': function(newentry) + { + this.data[this.data.length] = newentry; + }, + + /** + * Returns statistic + * + * This functions returns a hash table+ The keys are the different + * entry types and the values are the amount of these entries+ + * + * @access public + * @return array Hash Table with the data + */ + 'getStatistic': function() + { + var ret = array(); + for (var i=0; i=(iPages-iPageCountHalf)){iStartButton=iPages-iPageCount+1; +iEndButton=iPages}else{iStartButton=iCurrentPage-Math.ceil(iPageCount/2)+1;iEndButton=iStartButton+iPageCount-1 +}}}for(i=iStartButton;i<=iEndButton;i++){if(iCurrentPage!=i){sList+=''+i+"" +}else{sList+=''+i+""}}var an=oSettings.aanFeatures.p; +var anButtons,anStatic,nPaginateList;var fnClick=function(){var iTarget=(this.innerHTML*1)-1; +oSettings._iDisplayStart=iTarget*oSettings._iDisplayLength;fnCallbackDraw(oSettings); +return false};var fnFalse=function(){return false};for(i=0,iLen=an.length;iy)?1:0))},"string-desc":function(a,b){var x=a.toLowerCase(); +var y=b.toLowerCase();return((xy)?-1:0))},"html-asc":function(a,b){var x=a.replace(/<.*?>/g,"").toLowerCase(); +var y=b.replace(/<.*?>/g,"").toLowerCase();return((xy)?1:0))},"html-desc":function(a,b){var x=a.replace(/<.*?>/g,"").toLowerCase(); +var y=b.replace(/<.*?>/g,"").toLowerCase();return((xy)?-1:0))},"date-asc":function(a,b){var x=Date.parse(a); +var y=Date.parse(b);if(isNaN(x)){x=Date.parse("01/01/1970 00:00:00")}if(isNaN(y)){y=Date.parse("01/01/1970 00:00:00") +}return x-y},"date-desc":function(a,b){var x=Date.parse(a);var y=Date.parse(b);if(isNaN(x)){x=Date.parse("01/01/1970 00:00:00") +}if(isNaN(y)){y=Date.parse("01/01/1970 00:00:00")}return y-x},"numeric-asc":function(a,b){var x=a=="-"?0:a; +var y=b=="-"?0:b;return x-y},"numeric-desc":function(a,b){var x=a=="-"?0:a;var y=b=="-"?0:b; +return y-x}};_oExt.aTypes=[function(sData){if(typeof sData=="number"){return"numeric" +}else{if(typeof sData.charAt!="function"){return null}}var sValidFirstChars="0123456789-"; +var sValidChars="0123456789.";var Char;var bDecimal=false;Char=sData.charAt(0);if(sValidFirstChars.indexOf(Char)==-1){return null +}for(var i=1;i=parseInt(sThat,10)};this.fnSort=function(aaSort){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]); +oSettings.aaSorting=aaSort;_fnSort(oSettings)};this.fnSortListener=function(nNode,iColumn,fnCallback){_fnSortAttachListener(_fnSettingsFromNode(this[_oExt.iApiIndex]),nNode,iColumn,fnCallback) +};this.fnAddData=function(mData,bRedraw){if(mData.length===0){return[]}var aiReturn=[]; +var iTest;var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]);if(typeof mData[0]=="object"){for(var i=0; +i=oSettings.aiDisplay.length){oSettings._iDisplayStart-=oSettings._iDisplayLength; +if(oSettings._iDisplayStart<0){oSettings._iDisplayStart=0}}_fnCalculateEnd(oSettings); +_fnDraw(oSettings);var aData=oSettings.aoData[iAODataIndex]._aData.slice();if(typeof bNullRow!="undefined"&&bNullRow===true){oSettings.aoData[iAODataIndex]=null +}return aData};this.fnClearTable=function(bRedraw){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]); +_fnClearTable(oSettings);if(typeof bRedraw=="undefined"||bRedraw){_fnDraw(oSettings) +}};this.fnOpen=function(nTr,sHtml,sClass){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]); +this.fnClose(nTr);var nNewRow=document.createElement("tr");var nNewCell=document.createElement("td"); +nNewRow.appendChild(nNewCell);nNewCell.className=sClass;nNewCell.colSpan=_fnVisbleColumns(oSettings); +nNewCell.innerHTML=sHtml;var nTrs=$("tbody tr",oSettings.nTable);if($.inArray(nTr,nTrs)!=-1){$(nNewRow).insertAfter(nTr) +}if(!oSettings.oFeatures.bServerSide){oSettings.aoOpenRows.push({nTr:nNewRow,nParent:nTr}) +}return nNewRow};this.fnClose=function(nTr){var oSettings=_fnSettingsFromNode(this[_oExt.iApiIndex]); +for(var i=0;itr",oSettings.nTable)[0];var nTrFoot=$("tfoot:eq(0)>tr",oSettings.nTable)[0]; +var anTheadTh=[];var anTfootTh=[];for(i=0;i=_fnVisbleColumns(oSettings)){nTrHead.appendChild(anTheadTh[iCol]); +if(nTrFoot){nTrFoot.appendChild(anTfootTh[iCol])}for(i=0,iLen=oSettings.aoData.length; +itd:eq("+iBefore+")",oSettings.aoData[i].nTr)[0]) +}}oSettings.aoColumns[iCol].bVisible=true}else{nTrHead.removeChild(anTheadTh[iCol]); +if(nTrFoot){nTrFoot.removeChild(anTfootTh[iCol])}anTds=_fnGetTdNodes(oSettings);for(i=0,iLen=oSettings.aoData.length; +i=oSettings.fnRecordsDisplay())?0:oSettings.iInitDisplayStart; +oSettings.iInitDisplayStart=-1;_fnCalculateEnd(oSettings)}if(oSettings.aiDisplay.length!==0){var iStart=oSettings._iDisplayStart; +var iEnd=oSettings._iDisplayEnd;if(oSettings.oFeatures.bServerSide){iStart=0;iEnd=oSettings.aoData.length +}for(var j=iStart;jtr",oSettings.nTable)[0],_fnGetDataMaster(oSettings),oSettings._iDisplayStart,oSettings.fnDisplayEnd(),oSettings.aiDisplay) +}if(typeof oSettings.fnFooterCallback=="function"){oSettings.fnFooterCallback($("tfoot:eq(0)>tr",oSettings.nTable)[0],_fnGetDataMaster(oSettings),oSettings._iDisplayStart,oSettings.fnDisplayEnd(),oSettings.aiDisplay) +}var nBody=oSettings.nTable.getElementsByTagName("tbody");if(nBody[0]){var nTrs=nBody[0].childNodes; +for(i=nTrs.length-1;i>=0;i--){nTrs[i].parentNode.removeChild(nTrs[i])}for(i=0,iLen=anRows.length; +i"){nInsertNode=nInsertNode.parentNode}else{if(cOption=="l"&&oSettings.oFeatures.bPaginate&&oSettings.oFeatures.bLengthChange){nTmp=_fnFeatureHtmlLength(oSettings); +iPushFeature=1}else{if(cOption=="f"&&oSettings.oFeatures.bFilter){nTmp=_fnFeatureHtmlFilter(oSettings); +iPushFeature=1}else{if(cOption=="r"&&oSettings.oFeatures.bProcessing){nTmp=_fnFeatureHtmlProcessing(oSettings); +iPushFeature=1}else{if(cOption=="t"){nTmp=oSettings.nTable;iPushFeature=1}else{if(cOption=="i"&&oSettings.oFeatures.bInfo){nTmp=_fnFeatureHtmlInfo(oSettings); +iPushFeature=1}else{if(cOption=="p"&&oSettings.oFeatures.bPaginate){nTmp=_fnFeatureHtmlPaginate(oSettings); +iPushFeature=1}else{if(_oExt.aoFeatures.length!==0){var aoFeatures=_oExt.aoFeatures; +for(var k=0,kLen=aoFeatures.length;k';var jqFilter=$("input",nFilter); +jqFilter.val(oSettings.oPreviousSearch.sSearch.replace('"',"""));jqFilter.keyup(function(e){var n=oSettings.aanFeatures.f; +for(var i=0,iLen=n.length;i=0; +i--){var sData=_fnDataToSearch(oSettings.aoData[oSettings.aiDisplay[i]]._aData[iColumn],oSettings.aoColumns[iColumn].sType); +if(!rpSearch.test(sData)){oSettings.aiDisplay.splice(i,1);iIndexCorrector++}}}function _fnFilter(oSettings,sInput,iForce,bEscapeRegex){var i; +if(typeof iForce=="undefined"||iForce===null){iForce=0}if(_oExt.afnFiltering.length!==0){iForce=1 +}var asSearch=bEscapeRegex?_fnEscapeRegex(sInput).split(" "):sInput.split(" ");var sRegExpString="^(?=.*?"+asSearch.join(")(?=.*?")+").*$"; +var rpSearch=new RegExp(sRegExpString,"i");if(sInput.length<=0){oSettings.aiDisplay.splice(0,oSettings.aiDisplay.length); +oSettings.aiDisplay=oSettings.aiDisplayMaster.slice()}else{if(oSettings.aiDisplay.length==oSettings.aiDisplayMaster.length||oSettings.oPreviousSearch.sSearch.length>sInput.length||iForce==1||sInput.indexOf(oSettings.oPreviousSearch.sSearch)!==0){oSettings.aiDisplay.splice(0,oSettings.aiDisplay.length); +_fnBuildSearchArray(oSettings,1);for(i=0;i/g,"")}else{if(typeof sData=="string"){return sData.replace(/\n/g," ") +}}}return sData}function _fnSort(oSettings,bApplyClasses){var aaSort=[];var oSort=_oExt.oSort; +var aoData=oSettings.aoData;var iDataSort;var iDataType;var i,j,jLen;if(!oSettings.oFeatures.bServerSide&&(oSettings.aaSorting.length!==0||oSettings.aaSortingFixed!==null)){if(oSettings.aaSortingFixed!==null){aaSort=oSettings.aaSortingFixed.concat(oSettings.aaSorting) +}else{aaSort=oSettings.aaSorting.slice()}for(i=0;i=iColumns){for(i=0;i=0?oSettings._iDisplayStart-oSettings._iDisplayLength:0; +if(oSettings._iDisplayStart<0){oSettings._iDisplayStart=0}}else{if(sAction=="next"){if(oSettings._iDisplayLength>=0){if(oSettings._iDisplayStart+oSettings._iDisplayLength=0){var iPages=parseInt((oSettings.fnRecordsDisplay()-1)/oSettings._iDisplayLength,10)+1; +oSettings._iDisplayStart=(iPages-1)*oSettings._iDisplayLength}else{oSettings._iDisplayStart=0 +}}else{alert("DataTables warning: unknown paging action: "+sAction)}}}}return iOldStart!=oSettings._iDisplayStart +}function _fnFeatureHtmlInfo(oSettings){var nInfo=document.createElement("div");nInfo.className=oSettings.oClasses.sInfo; +if(typeof oSettings.aanFeatures.i=="undefined"){oSettings.aoDrawCallback.push({fn:_fnUpdateInfo,sName:"information"}); +if(oSettings.sTableId!==""){nInfo.setAttribute("id",oSettings.sTableId+"_info")}}return nInfo +}function _fnUpdateInfo(oSettings){if(!oSettings.oFeatures.bInfo||oSettings.aanFeatures.i.length===0){return +}var nFirst=oSettings.aanFeatures.i[0];if(oSettings.fnRecordsDisplay()===0&&oSettings.fnRecordsDisplay()==oSettings.fnRecordsTotal()){nFirst.innerHTML=oSettings.oLanguage.sInfoEmpty+oSettings.oLanguage.sInfoPostFix +}else{if(oSettings.fnRecordsDisplay()===0){nFirst.innerHTML=oSettings.oLanguage.sInfoEmpty+" "+oSettings.oLanguage.sInfoFiltered.replace("_MAX_",oSettings.fnRecordsTotal())+oSettings.oLanguage.sInfoPostFix +}else{if(oSettings.fnRecordsDisplay()==oSettings.fnRecordsTotal()){nFirst.innerHTML=oSettings.oLanguage.sInfo.replace("_START_",oSettings._iDisplayStart+1).replace("_END_",oSettings.fnDisplayEnd()).replace("_TOTAL_",oSettings.fnRecordsDisplay())+oSettings.oLanguage.sInfoPostFix +}else{nFirst.innerHTML=oSettings.oLanguage.sInfo.replace("_START_",oSettings._iDisplayStart+1).replace("_END_",oSettings.fnDisplayEnd()).replace("_TOTAL_",oSettings.fnRecordsDisplay())+" "+oSettings.oLanguage.sInfoFiltered.replace("_MAX_",oSettings.fnRecordsTotal())+oSettings.oLanguage.sInfoPostFix +}}}var n=oSettings.aanFeatures.i;if(n.length>1){var sInfo=nFirst.innerHTML;for(var i=1,iLen=n.length; +i'; +var nLength=document.createElement("div");if(oSettings.sTableId!==""&&typeof oSettings.aanFeatures.l=="undefined"){nLength.setAttribute("id",oSettings.sTableId+"_length") +}nLength.className=oSettings.oClasses.sLength;nLength.innerHTML=oSettings.oLanguage.sLengthMenu.replace("_MENU_",sStdMenu); +$('select option[value="'+oSettings._iDisplayLength+'"]',nLength).attr("selected",true); +$("select",nLength).change(function(e){var iVal=$(this).val();var n=oSettings.aanFeatures.l; +for(var i=0,iLen=n.length;ioSettings.aiDisplay.length||oSettings._iDisplayLength==-1){oSettings._iDisplayEnd=oSettings.aiDisplay.length +}else{oSettings._iDisplayEnd=oSettings._iDisplayStart+oSettings._iDisplayLength}}}function _fnConvertToWidth(sWidth,nParent){if(!sWidth||sWidth===null||sWidth===""){return 0 +}if(typeof nParent=="undefined"){nParent=document.getElementsByTagName("body")[0] +}var iWidth;var nTmp=document.createElement("div");nTmp.style.width=sWidth;nParent.appendChild(nTmp); +iWidth=nTmp.offsetWidth;nParent.removeChild(nTmp);return(iWidth)}function _fnCalculateColumnWidths(oSettings){var iTableWidth=oSettings.nTable.offsetWidth; +var iTotalUserIpSize=0;var iTmpWidth;var iVisibleColumns=0;var iColums=oSettings.aoColumns.length; +var i;var oHeaders=$("thead:eq(0)>th",oSettings.nTable);for(i=0;i';var sCalcHead="";var sCalcHtml=""; +for(i=0;i"+oSettings.aoColumns[i].sTitle+""; +if(oSettings.aoColumns[i].sWidth!==null){var sWidth="";if(oSettings.aoColumns[i].sWidth!==null){sWidth=' style="width:'+oSettings.aoColumns[i].sWidth+';"' +}sCalcHtml+="'+fnGetMaxLenString(oSettings,i)+"" +}else{sCalcHtml+=''+fnGetMaxLenString(oSettings,i)+""}}}sCalcHead+=""; +sCalcHtml+="";nCalcTmp=$(sTableTmp+sCalcHead+sCalcHtml+"")[0];nCalcTmp.style.width=iTableWidth+"px"; +nCalcTmp.style.visibility="hidden";nCalcTmp.style.position="absolute";oSettings.nTable.parentNode.appendChild(nCalcTmp); +var oNodes=$("tr:eq(1)>td",nCalcTmp);var iIndex;for(i=0;iiMax){iMax=oSettings.aoData[i]._aData[iCol].length; +iMaxIndex=i}}if(iMaxIndex>=0){return oSettings.aoData[iMaxIndex]._aData[iCol]}return"" +}function _fnArrayCmp(aArray1,aArray2){if(aArray1.length!=aArray2.length){return 1 +}for(var i=0;it<"F"ip>'}}if(typeof oInit.iDisplayStart!="undefined"&&typeof oSettings.iInitDisplayStart=="undefined"){oSettings.iInitDisplayStart=oInit.iDisplayStart; +oSettings._iDisplayStart=oInit.iDisplayStart}if(typeof oInit.bStateSave!="undefined"){oSettings.oFeatures.bStateSave=oInit.bStateSave; +_fnLoadState(oSettings,oInit);oSettings.aoDrawCallback.push({fn:_fnSaveState,sName:"state_save"}) +}if(typeof oInit.aaData!="undefined"){bUsePassedData=true}if(typeof oInit!="undefined"&&typeof oInit.aoData!="undefined"){oInit.aoColumns=oInit.aoData +}if(typeof oInit.oLanguage!="undefined"){if(typeof oInit.oLanguage.sUrl!="undefined"&&oInit.oLanguage.sUrl!==""){oSettings.oLanguage.sUrl=oInit.oLanguage.sUrl; +$.getJSON(oSettings.oLanguage.sUrl,null,function(json){_fnLanguageProcess(oSettings,json,true) +});bInitHandedOff=true}else{_fnLanguageProcess(oSettings,oInit.oLanguage,false)}}}else{oInit={} +}if(typeof oInit.asStripClasses=="undefined"){oSettings.asStripClasses.push(oSettings.oClasses.sStripOdd); +oSettings.asStripClasses.push(oSettings.oClasses.sStripEven)}var nThead=this.getElementsByTagName("thead"); +var nThs=nThead.length===0?null:_fnGetUniqueThs(nThead[0]);var bUseCols=typeof oInit.aoColumns!="undefined"; +for(i=0,iLen=bUseCols?oInit.aoColumns.length:nThs.length;imissing<\/span>'); + }, + // converts the given author data into HTML + authors2html: function(authorData) { + var authorsStr = ''; + for (var index = 0; index < authorData.length; index++) { + if (index > 0) { authorsStr += ", "; } + authorsStr += authorData[index].first +" " +authorData[index].last; + } + return htmlify(authorsStr); + }, + // adds links to the PDF or url of the item + links: function(entryData) { + var itemStr = ''; + if (entryData.url && entryData.url.match(/.*\.pdf/)) { + itemStr += ' (
open access<\/a>)'; + } else if (entryData.url) { + itemStr += ' (open access<\/a>)'; + } + if (entryData.prj) { + itemStr += ' (open source<\/a>)'; + } + + return itemStr; + }, + // adds links to the PDF or url of the item + doi: function(entryData) { + var itemStr = ''; + if (entryData.doi) { + itemStr += ' (doi<\/a>)'; + } + return itemStr; + }, + comment: function(entryData) { + var itemStr = ''; + if (entryData.comment) { + itemStr += ' ' + entryData.comment + '<\/strong>'; + } + return itemStr; + }, + pmid: function(entryData) { + var itemStr = ''; + if (entryData.pmid) { + itemStr += ' (pmid<\/a>)'; + } + return itemStr; + }, + // adds the bibtex link and the opening div with bibtex content + bibtex: function(entryData) { + var itemStr = ''; + itemStr += ' (' + + 'bib)"; + return itemStr; + }, + // generates the twitter link for the entry + tweet: function(entryData, bib) { + // url, via, text + var itemStr = ' (" + entryData.booktitle + + ", pp. " + entryData.pages + + ((entryData.address)?", " + entryData.address:"") + ".<\/em>"; + }, + article: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + entryData.title + ". " + entryData.journal + ", " + entryData.volume + + ((entryData.number)?"(" + entryData.number + ")":"")+ ", " + + "pp. " + entryData.pages + ". " + + ((entryData.address)?entryData.address + ".":"") + "<\/em>"; + }, + misc: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + entryData.title + ". " + + ((entryData.howpublished)?entryData.howpublished + ". ":"") + + ((entryData.note)?entryData.note + ".":""); + }, + mastersthesis: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + entryData.title + ". " + entryData.type + ". " + + entryData.organization + ", " + entryData.school + "."; + }, + techreport: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + entryData.title + ". " + entryData.institution + ". " + + entryData.number + ". " + entryData.type + "."; + }, + book: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + " " + entryData.title + "<\/em>, " + + entryData.publisher + ", " + entryData.year + + ((entryData.issn)?", ISBN: " + entryData.issn + ".":"."); + }, + inbook: function(entryData) { + return this.authors2html(entryData.author) + " (" + entryData.year + "). " + + entryData.chapter + " in " + entryData.title + "<\/em>, " + + ((entryData.editor)?" Edited by " + entryData.editor + ", ":"") + + entryData.publisher + ", pp. " + entryData.pages + "" + + ((entryData.series)?", " + entryData.series + "<\/em>":"") + + ((entryData.volume)?", Vol. " + entryData.volume + "":"") + + ((entryData.issn)?", ISBN: " + entryData.issn + "":"") + + "."; + }, + // weights of the different types of entries; used when sorting + importance: { + 'TITLE': 9999, + 'misc': 0, + 'manual': 10, + 'techreport': 20, + 'mastersthesis': 30, + 'inproceedings': 40, + 'incollection': 50, + 'proceedings': 60, + 'conference': 70, + 'article': 30, + 'phdthesis': 90, + 'inbook': 100, + 'book': 110, + 'unpublished': 120 + }, + // labels used for the different types of entries + labels: { + 'article': 'Journal', + 'book': 'Book', + 'conference': 'Talk', + 'inbook': 'Book chapter', + 'incollection': '', + 'inproceedings': 'Abstract', + 'manual': 'Manual', + 'mastersthesis': 'Thesis', + 'misc': 'Misc', + 'phdthesis': 'PhD Thesis', + 'proceedings': 'Conference proceeding', + 'techreport': 'Technical report', + 'unpublished': 'Unpublished'} + }; + // format a phd thesis similarly to masters thesis + bib2html.phdthesis = bib2html.mastersthesis; + // conference is the same as inproceedings + bib2html.conference = bib2html.inproceedings; + + // event handlers for the bibtex links + var EventHandlers = { + showbib: function showbib(event) { + $(this).next(".bibinfo").removeClass('hidden').addClass("open"); + $("#shutter").show(); + event.preventDefault(); + }, + hidebib: function hidebib(event) { + $("#shutter").hide(); + $(".bibinfo.open").removeClass("open").addClass("hidden"); + event.preventDefault(); + } + }; + + var Bib2HTML = function(data, $pubTable, options) { + this.options = options; + this.$pubTable = $pubTable; + this.stats = { }; + this.initialize(data); + }; + var bibproto = Bib2HTML.prototype; + bibproto.initialize = function initialize(data) { + var bibtex = new BibTex(); + bibtex.content = data; + bibtex.parse(); + var bibentries = [], len = bibtex.data.length; + var entryTypes = {}; + jQuery.extend(true, bib2html, this.options.bib2html); + for (var index = 0; index < len; index++) { + var item = bibtex.data[index]; + if (!item.year) { + item.year = this.options.defaultYear || "To Appear"; + } + var html = bib2html.entry2html(item, this); + bibentries.push([item.year, bib2html.labels[item.entryType], html]); + entryTypes[bib2html.labels[item.entryType]] = item.entryType; + this.updateStats(item); + } + jQuery.fn.dataTableExt.oSort['type-sort-asc'] = function(x, y) { + var item1 = bib2html.importance[entryTypes[x]], + item2 = bib2html.importance[entryTypes[y]]; + return ((item1 < item2) ? -1 : ((item1 > item2) ? 1 : 0)); + }; + jQuery.fn.dataTableExt.oSort['type-sort-desc'] = function(x, y) { + var item1 = bib2html.importance[entryTypes[x]], + item2 = bib2html.importance[entryTypes[y]]; + return ((item1 < item2) ? 1 : ((item1 > item2) ? -1 : 0)); + }; + var table = this.$pubTable.dataTable({ 'aaData': bibentries, + 'aaSorting': this.options.sorting, + 'aoColumns': [ { "sTitle": "Year" }, + { "sTitle": "Type", "sType": "type-sort", "asSorting": [ "desc", "asc" ] }, + { "sTitle": "Publication", "bSortable": false }], + 'bPaginate': false + }); + if (this.options.visualization) { + this.addBarChart(); + } + $("th", this.$pubTable).unbind("click").click(function(e) { + var $this = $(this), + $thElems = $this.parent().find("th"), + index = $thElems.index($this); + if ($this.hasClass("sorting_disabled")) { return; } + $this.toggleClass("sorting_asc").toggleClass("sorting_desc"); + + if (index === 0) { + table.fnSort( [[0, $thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"], + [1, $thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"]]); + } else { + table.fnSort( [[1, $thElems.eq(1).hasClass("sorting_asc")?"asc":"desc"], + [0, $thElems.eq(0).hasClass("sorting_asc")?"asc":"desc"]]); + } + }); + // attach the event handlers to the bib items + $(".biblink", this.$pubTable).live('click', EventHandlers.showbib); + $(".bibclose", this.$pubTable).live('click', EventHandlers.hidebib); + }; + // updates the stats, called whenever a new bibtex entry is parsed + bibproto.updateStats = function updateStats(item) { + if (!this.stats[item.year]) { + this.stats[item.year] = { 'count': 1, 'types': {} }; + this.stats[item.year].types[item.entryType] = 1; + } else { + this.stats[item.year].count += 1; + if (this.stats[item.year].types[item.entryType]) { + this.stats[item.year].types[item.entryType] += 1; + } else { + this.stats[item.year].types[item.entryType] = 1; + } + } + }; + // adds the barchart of year and publication types + bibproto.addBarChart = function addBarChart() { + var yearstats = [], max = 0; + $.each(this.stats, function(key, value) { + max = Math.max(max, value.count); + yearstats.push({'year': key, 'count': value.count, + 'item': value, 'types': value.types}); + }); + yearstats.sort(function(a, b) { + var diff = a.year - b.year; + if (!isNaN(diff)) { + return diff; + } else if (a.year < b.year) { + return -1; + } else if (a.year > b.year) { + return 1; + } + return 0; + }); + var chartIdSelector = "#" + this.$pubTable[0].id + "pubchart"; + var pubHeight = $(chartIdSelector).height()/max - 2; + var styleStr = chartIdSelector +" .year { width: " + + (100.0/yearstats.length) + "%; }" + + chartIdSelector + " .pub { height: " + pubHeight + "px; }"; + var legendTypes = []; + var stats2html = function(item) { + var types = [], + str = '
', + sum = 0; + $.each(item.types, function(type, value) { + types.push(type); + sum += value; + }); + types.sort(function(x, y) { + return bib2html.importance[y] - bib2html.importance[x]; + }); + str += '
'; + for (var i = 0; i < types.length; i++) { + var type = types[i]; + if (legendTypes.indexOf(type) === -1) { + legendTypes.push(type); + } + for (var j = 0; j < item.types[type]; j++) { + str += '
'; + } + } + return str + '
' + item.year + '
'; + }; + var statsHtml = ""; + yearstats.forEach(function(item) { + statsHtml += stats2html(item); + }); + var legendHtml = '
'; + for (var i = 0, l = legendTypes.length; i < l; i++) { + var legend = legendTypes[i]; + legendHtml += '' + bib2html.labels[legend]; + } + legendHtml += '
'; + $(chartIdSelector).html(statsHtml).after(legendHtml); + }; + + // Creates a new publication list to the HTML element with ID + // bibElemId. The bibsrc can be + // - a jQuery selector, in which case html of the element is used + // as the bibtex data + // - a URL, which is loaded and used as data. Note, that same-origin + // policy restricts where you can load the data. + // Supported options: + // - visualization: A boolean to control addition of the visualization. + // Defaults to true. + // - tweet: Twitter username to add Tweet links to bib items with a url field. + // - sorting: Control the default sorting of the list. Defaults to [[0, "desc"], + // [1, "desc"]]. See http://datatables.net/api fnSort for details + // on formatting. + // - bib2html: Can be used to override any of the functions or properties of + // the bib2html object. See above, starting around line 40. + return function(bibsrc, bibElemId, opts) { + var options = $.extend({}, {'visualization': true, + 'sorting': [[0, "desc"], [1, "desc"]]}, + opts); + var $pubTable = $("#" + bibElemId).addClass("bibtable"); + if ($("#shutter").size() === 0) { + $pubTable.before(''); + $("#shutter").click(EventHandlers.hidebib); + } + if (options.visualization) { + $pubTable.before('
'); + } + var $bibSrc = $(bibsrc); + if ($bibSrc.length) { // we found an element, use its HTML as bibtex + new Bib2HTML($bibSrc.html(), $pubTable, options); + $bibSrc.hide(); + } else { // otherwise we assume it is a URL + var callbackHandler = function(data) { + new Bib2HTML(data, $pubTable, options); + }; + $.get(bibsrc, callbackHandler, "text"); + } + }; +})(jQuery); \ No newline at end of file diff --git a/docs/javascripts/main.js b/docs/javascripts/main.js new file mode 100644 index 0000000..d8135d3 --- /dev/null +++ b/docs/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/docs/javascripts/menu_script.js b/docs/javascripts/menu_script.js new file mode 100755 index 0000000..5df9bef --- /dev/null +++ b/docs/javascripts/menu_script.js @@ -0,0 +1,72 @@ +(function($) { + + $.fn.menumaker = function(options) { + + var cssmenu = $(this), settings = $.extend({ + title: "Menu", + format: "dropdown", + sticky: false + }, options); + + return this.each(function() { + cssmenu.prepend(''); + $(this).find("#menu-button").on('click', function(){ + $(this).toggleClass('menu-opened'); + var mainmenu = $(this).next('ul'); + if (mainmenu.hasClass('open')) { + mainmenu.hide().removeClass('open'); + } + else { + mainmenu.show().addClass('open'); + if (settings.format === "dropdown") { + mainmenu.find('ul').show(); + } + } + }); + + cssmenu.find('li ul').parent().addClass('has-sub'); + + multiTg = function() { + cssmenu.find(".has-sub").prepend(''); + cssmenu.find('.submenu-button').on('click', function() { + $(this).toggleClass('submenu-opened'); + if ($(this).siblings('ul').hasClass('open')) { + $(this).siblings('ul').removeClass('open').hide(); + } + else { + $(this).siblings('ul').addClass('open').show(); + } + }); + }; + + if (settings.format === 'multitoggle') multiTg(); + else cssmenu.addClass('dropdown'); + + if (settings.sticky === true) cssmenu.css('position', 'fixed'); + + resizeFix = function() { + if ($( window ).width() > 768) { + cssmenu.find('ul').show(); + } + + if ($(window).width() <= 768) { + cssmenu.find('ul').hide().removeClass('open'); + } + }; + resizeFix(); + return $(window).on('resize', resizeFix); + + }); + }; +})(jQuery); + +(function($){ +$(document).ready(function(){ + +$("#cssmenu").menumaker({ + title: "Menu", + format: "multitoggle" +}); + +}); +})(jQuery); diff --git a/docs/javascripts/scale.fix.js b/docs/javascripts/scale.fix.js new file mode 100644 index 0000000..08716c0 --- /dev/null +++ b/docs/javascripts/scale.fix.js @@ -0,0 +1,20 @@ +fixScale = function(doc) { + + var addEvent = 'addEventListener', + type = 'gesturestart', + qsa = 'querySelectorAll', + scales = [1, 1], + meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; + + function fix() { + meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; + doc.removeEventListener(type, fix, true); + } + + if ((meta = meta[meta.length - 1]) && addEvent in doc) { + fix(); + scales = [.25, 1.6]; + doc[addEvent](type, fix, true); + } + +}; \ No newline at end of file diff --git a/docs/javascripts/toc.js b/docs/javascripts/toc.js new file mode 100644 index 0000000..90dd6fd --- /dev/null +++ b/docs/javascripts/toc.js @@ -0,0 +1,59 @@ +// https://github.com/ghiculescu/jekyll-table-of-contents +(function($){ + $.fn.toc = function(options) { + var defaults = { + noBackToTopLinks: false, + title: 'Jump to...', + listType: 'ol', // values: [ol|ul] + showSpeed: 'slow' + }, + settings = $.extend(defaults, options); + + var headers = $('h1, h2, h3, h4, h5, h6').filter(function() { + // get all headers with an ID + return this.id; + }), output = $(this); + if (!headers.length || headers.length < 3 || !output.length) { + return; + } + + var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); } + var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0]; + var return_to_top = ' '; + + var level = get_level(headers[0]), + this_level, + html = settings.title + " <"+settings.listType+">"; + headers.on('click', function() { + if (!settings.noBackToTopLinks) { + window.location.hash = this.id; + } + }) + .addClass('clickable-header') + .each(function(_, header) { + this_level = get_level(header); + if (!settings.noBackToTopLinks && this_level === highest_level) { + $(header).addClass('top-level-header').after(return_to_top); + } + if (this_level === level) // same level as before; same indenting + html += "
  • " + header.innerHTML + ""; + else if (this_level < level) // higher level than before; end parent ol + html += "
  • " + header.innerHTML + ""; + else if (this_level > level) // lower level than before; expand the previous to contain a ol + html += "<"+settings.listType+">
  • " + header.innerHTML + ""; + level = this_level; // update for the next one + }); + html += ""; + if (!settings.noBackToTopLinks) { + $(document).on('click', '.back-to-top', function() { + $(window).scrollTop(0); + window.location.hash = ''; + }); + } + if (0 !== settings.showSpeed) { + output.hide().html(html).show(settings.showSpeed); + } else { + output.html(html); + } + }; +})(jQuery); diff --git a/docs/params.json b/docs/params.json new file mode 100644 index 0000000..18e1ecc --- /dev/null +++ b/docs/params.json @@ -0,0 +1 @@ +{"name":"PCP Quality Assurance Protocol","tagline":"Scripts and documentation for the PCP's protocol for assessing data quality.","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.\r\n","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/docs/publications.md b/docs/publications.md new file mode 100644 index 0000000..5410130 --- /dev/null +++ b/docs/publications.md @@ -0,0 +1,4 @@ +--- +layout: page +title: PCP Quality Assessment Protocol +--- diff --git a/docs/qap_anatomical_example.png b/docs/qap_anatomical_example.png new file mode 100644 index 0000000..e8d079e Binary files /dev/null and b/docs/qap_anatomical_example.png differ diff --git a/docs/stylesheets/bib-publication-list.css b/docs/stylesheets/bib-publication-list.css new file mode 100644 index 0000000..a7bb3dd --- /dev/null +++ b/docs/stylesheets/bib-publication-list.css @@ -0,0 +1,41 @@ +span.undefined { color:red; } +.bibtable {width:100%; margin: 0 auto; clear: both;} +.bibchart { width: 100%; height: 100px; margin-bottom: 20px;} +.clear {clear:both;} +.year { z-index:10; position: relative; height: 100%; border-bottom: 1px solid black; display: inline-block;} +.yearlabel { position: absolute; bottom: -20px; text-align: center; width: 100%; font-size: smaller;} +.pub { border: 1px solid white; background-color: #eee; } +.conference { background-color: rgb(245,128,37); } +.inproceedings { background-color: #ccf; } +.article { background-color: #beb; } +.inbook { background-color: #eaa; } +.phdthesis { background-color: #999; } +.unpublished { background-color: #eae; } +.mastersthesis { background-color: #eea; } +.techreport { background-color: #b77; } +.legend .pub { width: 10px; height: 10px; display: inline-block; margin: 0 5px 0 15px;} +.legend { margin-bottom: 20px; text-align: center; width: 100%;} +table.display thead th { + padding: 3px 18px 3px 10px; + border-bottom: 1px solid black; + border-top: 1px solid black; + font-weight: bold; c + cursor: pointer; + cursor: hand; + background: #eee; } +table.display tfoot th { padding: 3px 10px; border-top: 1px solid black; font-weight: bold; } +table.display td { padding: 3px 10px; } +table.display td.center { text-align: center; } +.sorting_asc { background: url('../images/sort_asc.png') no-repeat center right; } +.sorting_desc { background: url('../images/sort_desc.png') no-repeat center right; } +.sorting { background: url('../images/sort_both.png') no-repeat center right; } +.sorting_asc_disabled { background: url('../images/sort_asc_disabled.png') no-repeat center right; } +.sorting_desc_disabled { background: url('../images/sort_desc_disabled.png') no-repeat center right; } +tr {font-size: 14px; text-align: left;} +tr.odd { background-color: white;} +tr.even { background-color: #eee; } +div.hidden { display: none;} +div.bibinfo { width: 80%; position: fixed; top: 100px; left: 10%; background-color: #bbb; border: 3px solid #fff; padding: 10px; -moz-border-radius:10px; -webkit-border-radius:10px; -o-border-radius:10px; border-radius:10px; z-index: 50;} +#shutter { background-color: #555; opacity: 0.7; width:100%; height: 100%; position: fixed; top: 0; left:0; z-index: 20;} +a.bibclose { background-color: #BBBBBB; border: 3px solid #FFFFFF; color: black; float: left; font-size: 20px; height: 20px; left: -25px; line-height: 20px; padding: 3px; position: relative; text-align: center; text-decoration: none; top: -25px; width: 20px; -moz-border-radius:15px; -webkit-border-radius:15px; -o-border-radius:15px; border-radius:15px; } +div.bibinfo pre { clear:both; } diff --git a/docs/stylesheets/pygment_trac.css b/docs/stylesheets/pygment_trac.css new file mode 100644 index 0000000..e65cedf --- /dev/null +++ b/docs/stylesheets/pygment_trac.css @@ -0,0 +1,70 @@ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f0f3f3; } +.highlight .c { color: #0099FF; font-style: italic } /* Comment */ +.highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ +.highlight .k { color: #006699; font-weight: bold } /* Keyword */ +.highlight .o { color: #555555 } /* Operator */ +.highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #009999 } /* Comment.Preproc */ +.highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ +.highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ +.highlight .go { color: #AAAAAA } /* Generic.Output */ +.highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #99CC66 } /* Generic.Traceback */ +.highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #006699 } /* Keyword.Pseudo */ +.highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #FF6600 } /* Literal.Number */ +.highlight .s { color: #CC3300 } /* Literal.String */ +.highlight .na { color: #330099 } /* Name.Attribute */ +.highlight .nb { color: #336666 } /* Name.Builtin */ +.highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ +.highlight .no { color: #336600 } /* Name.Constant */ +.highlight .nd { color: #9999FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #CC00FF } /* Name.Function */ +.highlight .nl { color: #9999FF } /* Name.Label */ +.highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #003333 } /* Name.Variable */ +.highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #FF6600 } /* Literal.Number.Float */ +.highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ +.highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ +.highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ +.highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ +.highlight .sc { color: #CC3300 } /* Literal.String.Char */ +.highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #CC3300 } /* Literal.String.Double */ +.highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ +.highlight .si { color: #AA0000 } /* Literal.String.Interpol */ +.highlight .sx { color: #CC3300 } /* Literal.String.Other */ +.highlight .sr { color: #33AAAA } /* Literal.String.Regex */ +.highlight .s1 { color: #CC3300 } /* Literal.String.Single */ +.highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ +.highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #003333 } /* Name.Variable.Class */ +.highlight .vg { color: #003333 } /* Name.Variable.Global */ +.highlight .vi { color: #003333 } /* Name.Variable.Instance */ +.highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/docs/stylesheets/stylesheet.css b/docs/stylesheets/stylesheet.css new file mode 100644 index 0000000..8c4a5de --- /dev/null +++ b/docs/stylesheets/stylesheet.css @@ -0,0 +1,949 @@ +/******************************************************************************* +Slate Theme for GitHub Pages +by Jason Costello, @jsncostello +*******************************************************************************/ + +@import url(pygment_trac.css); + +/******************************************************************************* +MeyerWeb Reset +*******************************************************************************/ + +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; +} + +/* HTML5 display-role reset for older browsers */ +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; +} + +ol, ul { + list-style: none; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +/******************************************************************************* +Theme Styles +*******************************************************************************/ + +body { + padding: 50px 0; + box-sizing: border-box; + color:#373737; + /*background: #212121 url("../images/big_mont.jpg") no-repeat 0 0;*/ + background:#d6c9b8; + font-size: 16px; + font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; + line-height: 1.5; + -webkit-font-smoothing: antialiased; +} + +h1, h2, h3, h4, h5, h6 { + margin: 10px 0; + font-weight: 700; + color:#222222; + font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; + letter-spacing: -1px; +} + +h1 { + font-size: 36px; + font-weight: 700; +} + +h2 { + padding-bottom: 0px; + font-size: 30px; +} + +h3 { + font-size: 24px; +} + +h4 { + font-size: 21px; +} + +h5 { + font-size: 18px; +} + +h6 { + font-size: 16px; +} + +p { + margin: 10px 0 15px 0; +} + +footer p { + color: #f2f2f2; +} + +a { + text-decoration: none; + color: #11772d; + text-shadow: none; + + transition: color 0.5s ease; + transition: text-shadow 0.5s ease; + -webkit-transition: color 0.5s ease; + -webkit-transition: text-shadow 0.5s ease; + -moz-transition: color 0.5s ease; + -moz-transition: text-shadow 0.5s ease; + -o-transition: color 0.5s ease; + -o-transition: text-shadow 0.5s ease; + -ms-transition: color 0.5s ease; + -ms-transition: text-shadow 0.5s ease; +} + +a:hover, a:focus {text-decoration: underline;} + +footer a { + color: #F2F2F2; + text-decoration: underline; +} + +em { + font-style: italic; +} + +strong { + font-weight: bold; +} + +sub, sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +img { + position: relative; + margin: 0 auto; + max-width: 739px; + /*padding: 5px; + margin: 10px 20px 0px 10px;*/ +} + +.imgframe +{ + background:#ffffff; + /*padding:12px; + border:1px solid #999999;*/ + + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; +} + +p img { + display: inline; + margin: 0; + padding: 0; + vertical-align: middle; + text-align: center; + border: none; +} + +pre, code { + width: 100%; + color: #222; + background-color: #fff; + + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 14px; + + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +pre { + width: 100%; + padding: 10px; + box-shadow: 0 0 10px rgba(0,0,0,.1); + overflow: auto; +} + +code { + padding: 3px; + margin: 0 3px; + box-shadow: 0 0 10px rgba(0,0,0,.1); +} + +pre code { + display: block; + box-shadow: none; +} + +blockquote { + color: #666; + margin-bottom: 20px; + padding: 0 0 0 20px; + border-left: 3px solid #bbb; +} + + +ul, ol, dl { + margin-bottom: 15px +} + +ul { + list-style: inside; + padding-left: 20px; +} + +ol { + list-style: decimal inside; + padding-left: 20px; +} + +dl dt { + font-weight: bold; +} + +dl dd { + padding-left: 20px; + font-style: italic; +} + +dl p { + padding-left: 20px; + font-style: italic; +} + +hr { + height: 1px; + margin-bottom: 5px; + border: none; + background: url('../images/bg_hr.png') repeat-x center; +} + +/* +table { + border: 1px solid #373737; + margin-bottom: 20px; + text-align: left; + } + +th { + font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; + padding: 10px; + background: #373737; + color: #fff; + } + +td { + padding: 10px; + border: 1px solid #373737; + } +*/ +form { + background: #f2f2f2; + padding: 20px; +} + +/******************************************************************************* +Full-Width Styles +*******************************************************************************/ + +.outer { + width: 100%; +} + +.inner { + max-width: 800px; + padding: 20px 10px; + margin: 0 auto; +} + +#container { + + /*background: #2d1318;*/ + background: #333; + /*min-height: 595px;*/ + + width: 860px; + margin: 0 auto; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -ms-border-radius: 8px; + -o-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + +} + +#container_box { + + /*background: #FFF;*/ + /*min-height: 595px;*/ + + width: 20%; + float: left; + margin: 0px auto; + background: #fff; + -webkit-border-radius: 8px; + -moz-border-radius: 8px; + -ms-border-radius: 8px; + -o-border-radius: 8px; + border-radius: 8px; + -webkit-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + -moz-box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + box-shadow: rgba(0, 0, 0, 0.2) 0 0 0 1px, rgba(0, 0, 0, 0.45) 0 3px 10px; + +} + +#boxes{ + height: 600px; +} +.small { + + background-color: #fff; + width: 400px; + border: 0px solid #fff; + border-radius:4px; + box-shadow: 3px 6px 7px 1px rgba(0, 0, 0, 0.6); + -moz-box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.6); + -webkit-box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.6); +} + +.small_blank { +width: 400px; +background-color:; #333 +} + +.thumbnail { +width: 380px; +height: 300px; +margin: 10px 10px 10px 10px; +position: relative; +top: 40px; +} + +.thumbnail a { + color: #251; +} + +.thumbnail img { + position: relative; + margin: 0 auto; + max-width: 739px; + padding: 0px; + margin: 0px 0px 0px 0px; +} + +.thumbnail .overlay { +background: url(../images/overlay.png) no-repeat; +display: block; +position: absolute; +height: 300px; +width: 380px; +left: 0px; +top: 0px; +} + + +.entry { +position: relative; +margin: 15px 15px 15px 15px; +height: 500px; + +float: left; +} + +.entry-content { +padding-bottom: 10px; +padding-top: 30px; +padding-left: 10px; +padding-right: 10px; +} + +.bottom-bg { +background: url(images/entry-top-bg.png) repeat-x top left; +overflow: hidden; +} + +.bottom-bg .excerpt { +padding: 10px 17px 0px; +height: 75px; +} + +h2.title { +padding: 0px 15px; +position: absolute; +top: -5px; +} + +h2.title a{ +color:#555; +} +#forkme_banner { + display: block; + position: absolute; + top:0; + right: 10px; + z-index: 10; + padding: 10px 50px 10px 10px; + color: #fff; + background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; + font-weight: 700; + box-shadow: 0 0 10px rgba(0,0,0,.5); + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; +} + +#header_wrap { + background: #d75920; +} + +#header_wrap .inner { + padding: 40px 10px 1px 10px; +} + +#header_wrap .nav-global li { + display: inline-block; + *display: inline; + zoom: 1; + line-height: normal; + letter-spacing: normal; + margin-right: 32px; + margin-left: -18px; + word-spacing: normal; + vertical-align: middle; +} + +#header_wrap .nav-global a { + color: #fff; + font-size: 24px; + font-weight: 300; + background: none; + text-shadow: none; +} + +#project_title { + margin: 0px 10px; + color: #fff; + font-size: 40px; + font-weight: 700; + text-shadow: #111 0px 0px 10px; +} + +#project_tagline { + color: #fff; + font-size: 24px; + font-weight: 300; + background: none; + text-shadow: none; +} + +#downloads { + position: absolute; + width: 210px; + z-index: 10; + bottom: -40px; + right: 0; + height: 70px; + background: url('../images/icon_download.png') no-repeat 0% 90%; +} + +.zip_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom left; +} + +.tar_download_link { + display: block; + float: right; + width: 90px; + height:70px; + text-indent: -5000px; + overflow: hidden; + background: url(../images/sprite_download.png) no-repeat bottom right; + margin-left: 10px; +} + +.zip_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top left; +} + +.tar_download_link:hover { + background: url(../images/sprite_download.png) no-repeat top right; +} + +#main_content_wrap { + background: #fff; + border-top: 1px solid #111; + border-bottom: 1px solid #111; +} + +#main_content { + padding-top: 40px; +} + +#footer_wrap { + background: #d75920; +} + + + +/******************************************************************************* +Small Device Styles +*******************************************************************************/ + +@media screen and (max-width: 480px) { + body { + font-size:14px; + } + + #downloads { + display: none; + } + + .inner { + min-width: 320px; + max-width: 480px; + } + + #project_title { + font-size: 32px; + } + + h1 { + font-size: 28px; + } + + h2 { + font-size: 24px; + } + + h3 { + font-size: 21px; + } + + h4 { + font-size: 18px; + } + + h5 { + font-size: 14px; + } + + h6 { + font-size: 12px; + } + + code, pre { + min-width: 320px; + max-width: 480px; + font-size: 11px; + } + +} + +/* --- for dropdown menus from cssmenumaker.com --- */ +#cssmenu{ + margin: 0px 0px 0px 0px; + padding: 0; + border: 0; + list-style: none; + line-height: 1; + display: block; + position: relative; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +#cssmenu ul, +#cssmenu ul li, +#cssmenu ul li a, +#cssmenu #menu-button { + z-index:1000; + margin: 0px 0px 0px 0px; + padding: 0; + border: 0; + list-style: none; + line-height: 1; + display: block; + position: relative; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + /*text-shadow: #111 0px 0px 10px;*/ +} +#cssmenu:after, +#cssmenu > ul:after { + content: "."; + display: block; + clear: both; + visibility: hidden; + line-height: 0; + height: 0; +} +#cssmenu #menu-button { + display: none; +} +#cssmenu { + background: #11772d +} +#cssmenu > ul > li { + float: left; +} +#cssmenu.align-center > ul { + font-size: 0; + text-align: center; +} +#cssmenu.align-center > ul > li { + display: inline-block; + float: none; +} +#cssmenu.align-center ul ul { + text-align: left; +} +#cssmenu.align-right > ul > li { + float: right; +} +#cssmenu > ul > li > a { + padding: 8px; + color: #fff; + font-size: 24px; + font-weight: 500; + text-decoration: none; + /*font-weight: 700; + text-transform: uppercase;*/ +} +#cssmenu > ul > li:hover > a { + color: #ffffff; +} +/* +#cssmenu > ul > li.has-sub > a { + padding-right: 30px; +} +#cssmenu > ul > li.has-sub > a:after { + position: absolute; + top: 22px; + right: 11px; + width: 8px; + height: 2px; + display: block; + background: #dddddd; + content: ''; +} + +#cssmenu > ul > li.has-sub > a:before { + position: absolute; + top: 19px; + right: 14px; + display: block; + width: 2px; + height: 8px; + background: #dddddd; + content: ''; + -webkit-transition: all .25s ease; + -moz-transition: all .25s ease; + -ms-transition: all .25s ease; + -o-transition: all .25s ease; + transition: all .25s ease; +}*/ +#cssmenu > ul > li.has-sub:hover > a:before { + top: 23px; + height: 0; +} +#cssmenu ul ul { + position: absolute; + left: -9999px; +} +#cssmenu.align-right ul ul { + text-align: right; +} +#cssmenu ul ul li { + height: 0; + -webkit-transition: all .25s ease; + -moz-transition: all .25s ease; + -ms-transition: all .25s ease; + -o-transition: all .25s ease; + transition: all .25s ease; +} +#cssmenu li:hover > ul { + left: auto; +} +#cssmenu.align-right li:hover > ul { + left: auto; + right: 0; +} +#cssmenu li:hover > ul > li { + height: 35px; +} +#cssmenu ul ul ul { + margin-left: 100%; + top: 0; +} +#cssmenu.align-right ul ul ul { + margin-left: 0; + margin-right: 100%; +} +#cssmenu ul ul li a { + border-bottom: 1px solid rgba(150, 150, 150, 0.15); + padding: 11px 15px; + width: 160px; + font-size: 20px; + text-decoration: none; + color: #fff; + font-weight: 500; + background: #d75920; +} +#cssmenu ul ul li:last-child > a, +#cssmenu ul ul li.last-item > a { + border-bottom: 0; +} +#cssmenu ul ul li:hover > a, +#cssmenu ul ul li a:hover { + color: #ffffff; +} +#cssmenu ul ul li.has-sub > a:after { + position: absolute; + top: 16px; + right: 11px; + width: 8px; + height: 2px; + display: block; + background: #dddddd; + content: ''; +} +#cssmenu.align-right ul ul li.has-sub > a:after { + right: auto; + left: 11px; +} +#cssmenu ul ul li.has-sub > a:before { + position: absolute; + top: 13px; + right: 14px; + display: block; + width: 2px; + height: 8px; + background: #dddddd; + content: ''; + -webkit-transition: all .25s ease; + -moz-transition: all .25s ease; + -ms-transition: all .25s ease; + -o-transition: all .25s ease; + transition: all .25s ease; +} +#cssmenu.align-right ul ul li.has-sub > a:before { + right: auto; + left: 14px; +} +#cssmenu ul ul > li.has-sub:hover > a:before { + top: 17px; + height: 0; +} +@media all and (max-width: 768px), only screen and (-webkit-min-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (min--moz-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (-o-min-device-pixel-ratio: 2/1) and (max-width: 1024px), only screen and (min-device-pixel-ratio: 2) and (max-width: 1024px), only screen and (min-resolution: 192dpi) and (max-width: 1024px), only screen and (min-resolution: 2dppx) and (max-width: 1024px) { + #cssmenu { + width: 100%; + } + #cssmenu ul { + width: 100%; + display: none; + } + #cssmenu.align-center > ul { + text-align: left; + } + #cssmenu ul li { + width: 100%; + border-top: 1px solid rgba(120, 120, 120, 0.2); + } + #cssmenu ul ul li, + #cssmenu li:hover > ul > li { + height: auto; + } + #cssmenu ul li a, + #cssmenu ul ul li a { + width: 100%; + border-bottom: 0; + } + #cssmenu > ul > li { + float: none; + } + #cssmenu ul ul li a { + padding-left: 25px; + } + #cssmenu ul ul ul li a { + padding-left: 35px; + } + #cssmenu ul ul li a { + color: #dddddd; + background: none; + } + #cssmenu ul ul li:hover > a, + #cssmenu ul ul li.active > a { + color: #ffffff; + } + #cssmenu ul ul, + #cssmenu ul ul ul, + #cssmenu.align-right ul ul { + position: relative; + left: 0; + width: 100%; + margin: 0; + text-align: left; + } + #cssmenu > ul > li.has-sub > a:after, + #cssmenu > ul > li.has-sub > a:before, + #cssmenu ul ul > li.has-sub > a:after, + #cssmenu ul ul > li.has-sub > a:before { + display: none; + } + #cssmenu #menu-button { + display: block; + padding: 17px; + color: #fff; + cursor: pointer; + font-size: 24px; + /*text-transform: uppercase*/; + font-weight: 700; + } + #cssmenu #menu-button:after { + position: absolute; + top: 22px; + right: 17px; + display: block; + height: 4px; + width: 20px; + border-top: 2px solid #dddddd; + border-bottom: 2px solid #dddddd; + content: ''; + } + #cssmenu #menu-button:before { + position: absolute; + top: 16px; + right: 17px; + display: block; + height: 2px; + width: 20px; + background: #dddddd; + content: ''; + } + #cssmenu #menu-button.menu-opened:after { + top: 23px; + border: 0; + height: 2px; + width: 15px; + background: #ffffff; + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } + #cssmenu #menu-button.menu-opened:before { + top: 23px; + background: #ffffff; + width: 15px; + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); + } + + #cssmenu .submenu-button { + position: absolute; + z-index: 99; + right: 0; + top: 0; + display: block; + border-left: 1px solid rgba(120, 120, 120, 0.2); + height: 46px; + width: 46px; + cursor: pointer; + } + #cssmenu .submenu-button.submenu-opened { + background: #262626; + } + + + #cssmenu ul ul .submenu-button { + height: 34px; + width: 34px; + } + + + #cssmenu .submenu-button:after { + position: absolute; + top: 22px; + right: 19px; + width: 8px; + height: 2px; + display: block; + background: #dddddd; + content: ''; + } + #cssmenu ul ul .submenu-button:after { + top: 15px; + right: 13px; + } + #cssmenu .submenu-button.submenu-opened:after { + background: #ffffff; + } + #cssmenu .submenu-button:before { + position: absolute; + top: 19px; + right: 22px; + display: block; + width: 2px; + height: 8px; + background: #dddddd; + content: ''; + } + #cssmenu ul ul .submenu-button:before { + top: 12px; + right: 16px; + } + #cssmenu .submenu-button.submenu-opened:before { + display: none; + } +}