├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug-report.md │ └── feature-request.md └── workflows │ ├── bandit.yml │ ├── docker-image.yml │ ├── pep8.yml │ ├── python-publish.yml │ ├── static.yml │ └── unittest.yml ├── LICENSE ├── README.md ├── TODO.md ├── docker ├── Dockerfile ├── README.md ├── remove.sh └── start.sh ├── docs ├── github │ └── graphical_resources │ │ ├── IPRoyal-Logo_Transparent_500x500.png │ │ ├── Logo-Without_background-MetaDetective.png │ │ ├── Logo-Without_background-Without_text-MetaDetective.png │ │ ├── MetaDetective_promotional_trailer.mp4 │ │ ├── Screenshot-MetaDetective_Demo.png │ │ ├── Screenshot-MetaDetective_HTML_Export_Demo.png │ │ └── Screenshot-MetaDetective_Scraping_Demo.png └── website │ ├── css │ ├── base.css │ ├── fonts.css │ ├── ionicons │ │ ├── css │ │ │ ├── ionicons.css │ │ │ └── ionicons.min.css │ │ └── fonts │ │ │ ├── ionicons.eot │ │ │ ├── ionicons.svg │ │ │ ├── ionicons.ttf │ │ │ └── ionicons.woff │ ├── main.css │ ├── micons │ │ ├── fonts │ │ │ ├── icomoon.eot │ │ │ ├── icomoon.svg │ │ │ ├── icomoon.ttf │ │ │ └── icomoon.woff │ │ └── micons.css │ └── vendor.css │ ├── favicon.png │ ├── fonts │ ├── merriweather │ │ ├── merriweather-black-webfont.eot │ │ ├── merriweather-black-webfont.svg │ │ ├── merriweather-black-webfont.ttf │ │ ├── merriweather-black-webfont.woff │ │ ├── merriweather-bold-webfont.eot │ │ ├── merriweather-bold-webfont.svg │ │ ├── merriweather-bold-webfont.ttf │ │ ├── merriweather-bold-webfont.woff │ │ ├── merriweather-bolditalic-webfont.eot │ │ ├── merriweather-bolditalic-webfont.svg │ │ ├── merriweather-bolditalic-webfont.ttf │ │ ├── merriweather-bolditalic-webfont.woff │ │ ├── merriweather-heavyitalic-webfont.eot │ │ ├── merriweather-heavyitalic-webfont.svg │ │ ├── merriweather-heavyitalic-webfont.ttf │ │ ├── merriweather-heavyitalic-webfont.woff │ │ ├── merriweather-italic-webfont.eot │ │ ├── merriweather-italic-webfont.svg │ │ ├── merriweather-italic-webfont.ttf │ │ ├── merriweather-italic-webfont.woff │ │ ├── merriweather-light-webfont.eot │ │ ├── merriweather-light-webfont.svg │ │ ├── merriweather-light-webfont.ttf │ │ ├── merriweather-light-webfont.woff │ │ ├── merriweather-lightitalic-webfont.eot │ │ ├── merriweather-lightitalic-webfont.svg │ │ ├── merriweather-lightitalic-webfont.ttf │ │ ├── merriweather-lightitalic-webfont.woff │ │ ├── merriweather-regular-webfont.eot │ │ ├── merriweather-regular-webfont.svg │ │ ├── merriweather-regular-webfont.ttf │ │ └── merriweather-regular-webfont.woff │ ├── montserrat │ │ ├── montserrat-bold-webfont.eot │ │ ├── montserrat-bold-webfont.svg │ │ ├── montserrat-bold-webfont.ttf │ │ ├── montserrat-bold-webfont.woff │ │ ├── montserrat-regular-webfont.eot │ │ ├── montserrat-regular-webfont.svg │ │ ├── montserrat-regular-webfont.ttf │ │ └── montserrat-regular-webfont.woff │ └── raleway │ │ ├── raleway-bold-webfont.eot │ │ ├── raleway-bold-webfont.svg │ │ ├── raleway-bold-webfont.ttf │ │ ├── raleway-bold-webfont.woff │ │ ├── raleway-extrabold-webfont.eot │ │ ├── raleway-extrabold-webfont.svg │ │ ├── raleway-extrabold-webfont.ttf │ │ ├── raleway-extrabold-webfont.woff │ │ ├── raleway-extralight-webfont.eot │ │ ├── raleway-extralight-webfont.svg │ │ ├── raleway-extralight-webfont.ttf │ │ ├── raleway-extralight-webfont.woff │ │ ├── raleway-heavy-webfont.eot │ │ ├── raleway-heavy-webfont.svg │ │ ├── raleway-heavy-webfont.ttf │ │ ├── raleway-heavy-webfont.woff │ │ ├── raleway-light-webfont.eot │ │ ├── raleway-light-webfont.svg │ │ ├── raleway-light-webfont.ttf │ │ ├── raleway-light-webfont.woff │ │ ├── raleway-medium-webfont.eot │ │ ├── raleway-medium-webfont.svg │ │ ├── raleway-medium-webfont.ttf │ │ ├── raleway-medium-webfont.woff │ │ ├── raleway-regular-webfont.eot │ │ ├── raleway-regular-webfont.svg │ │ ├── raleway-regular-webfont.ttf │ │ ├── raleway-regular-webfont.woff │ │ ├── raleway-semibold-webfont.eot │ │ ├── raleway-semibold-webfont.svg │ │ ├── raleway-semibold-webfont.ttf │ │ ├── raleway-semibold-webfont.woff │ │ ├── raleway-thin-webfont.eot │ │ ├── raleway-thin-webfont.svg │ │ ├── raleway-thin-webfont.ttf │ │ └── raleway-thin-webfont.woff │ ├── images │ ├── footer-logo.png │ ├── intro-bg.jpg │ ├── logo.png │ └── play-button.png │ ├── index.html │ └── js │ ├── jquery-1.11.3.min.js │ ├── jquery-migrate-1.2.1.min.js │ ├── main.js │ ├── modernizr.js │ └── plugins.js ├── examples ├── Black_Organization.png ├── MetaDetective-APTX_4869_report.pdf ├── MetaDetective-Kogoro_s_Choice.pdf ├── MetaDetective-Scuba_Diving_Murder_Case.pdf ├── MetaDetective.docx └── MetaDetective.png ├── pyproject.toml ├── src └── MetaDetective │ └── MetaDetective.py └── tests └── test_MetaDetective.py /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | # github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | # patreon: # Replace with a single Patreon username 5 | # open_collective: # Replace with a single Open Collective username 6 | # ko_fi: # Replace with a single Ko-fi username 7 | # tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | # community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | # liberapay: # Replace with a single Liberapay username 10 | # issuehunt: # Replace with a single IssueHunt username 11 | # lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | # polar: # Replace with a single Polar username 13 | # buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | # thanks_dev: # Replace with a single thanks.dev username 15 | # custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | 17 | custom: ['https://iproyal.com/?r=848799'] 18 | 19 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Your detailed bug reports are pivotal in elevating this project's quality. 4 | Your expertise in identifying issues is deeply valued and appreciated. 5 | title: "[ISSUE] Problem Encountered" 6 | labels: bug 7 | assignees: franckferman 8 | 9 | --- 10 | 11 | ## Problem Summary 12 | _Provide a clear and concise summary of the encountered issue._ 13 | 14 | ## Steps to Reproduce 15 | Provide a step-by-step description on how to reproduce the anomaly: 16 | 17 | 1. Command initiated: `...` 18 | 2. During the process: `....` 19 | 3. Observed issue: `....` 20 | 4. Output/response anomaly: `...` 21 | 22 | ## Expected Outcome 23 | _Describe the anticipated result after executing the provided steps._ 24 | 25 | ## Visual Evidence 26 | If possible, attach screenshots to support your description. 27 | 28 | ## Technical Details 29 | 30 | ### Operating System 31 | 32 | - **Linux:** [e.g. Linux root 4.19.0-6-amd64 #1 SMP Debian 4.19.67-2+deb10u1 (2019-09-20) x86_64 GNU/Linux] 33 | *Retrieval:* `uname -a` 34 | 35 | - **Windows:** [e.g. Microsoft Windows 10 Pro DevBox 10.0.15063 Multiprocessor Free 64-bit] 36 | *Retrieval:* 37 | ```powershell 38 | $Properties = 'Caption', 'CSName', 'Version', 'BuildType', 'OSArchitecture' 39 | Get-CimInstance Win32_OperatingSystem | Select-Object $Properties | Format-Table -AutoSize 40 | ``` 41 | 42 | ### Software Versions 43 | 44 | - **Python**: [e.g. Python 3.11.4] 45 | *Retrieval:* `python3 -V` 46 | 47 | - **Exiftool**: [e.g. 12.56] 48 | *Retrieval:* `exiftool -ver` 49 | 50 | - **MetaDetective**: [e.g. 1.0.8] 51 | 52 | ### Docker (if used) 53 | 54 | - **Image Version**: [e.g. "1.0.1"] 55 | 56 | ## Additional Information 57 | 58 | Provide any other pertinent details or context regarding the issue. 59 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Clearly outline the primary goal of this feature request. 4 | title: "[FEATURE]" 5 | labels: enhancement 6 | assignees: franckferman 7 | 8 | --- 9 | 10 | **Problem Nexus:** 11 | _Can you link this feature request to an existing problem or limitation?_ 12 | Provide a precise and thorough depiction of the issue. For instance, "The current workflow requires manual data entry, leading to inefficiencies and potential for error." 13 | 14 | **Envisioned Solution:** 15 | _Detail the desired feature or enhancement._ 16 | Expound upon how you imagine this feature will function, how it will address the problem, and the advantages it will introduce. 17 | 18 | **Alternative Strategies Assessed:** 19 | _Have you thought of other potential solutions?_ 20 | List and briefly explain other solutions or functionalities you've considered. Highlight why they might be less optimal than your proposed solution. 21 | 22 | **Implications and Integration:** 23 | _How will this feature fit into the current system?_ 24 | Discuss any potential interactions with existing features, how it aligns with the project's goals, or any other relevant integrations. 25 | 26 | **Visual Demonstrations (if applicable):** 27 | _Do you have visual aids or mock-ups?_ 28 | Embed any diagrams, wireframes, or screenshots that can provide clarity on the desired feature's function and integration. 29 | -------------------------------------------------------------------------------- /.github/workflows/bandit.yml: -------------------------------------------------------------------------------- 1 | name: bandit 2 | 3 | on: 4 | push: 5 | branches: [ "stable" ] 6 | paths: 7 | - 'src/MetaDetective/MetaDetective.py' 8 | pull_request: 9 | branches: [ "stable" ] 10 | paths: 11 | - 'src/MetaDetective/MetaDetective.py' 12 | 13 | jobs: 14 | security-check: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout Repository 19 | uses: actions/checkout@v2 20 | 21 | - name: Set up Python 22 | uses: actions/setup-python@v2 23 | with: 24 | python-version: 3.11 25 | 26 | - name: Install Bandit 27 | run: pip install bandit 28 | 29 | - name: Run Bandit 30 | run: bandit ./src/MetaDetective/MetaDetective.py -s B404,B607,B603,B310 31 | 32 | -------------------------------------------------------------------------------- /.github/workflows/docker-image.yml: -------------------------------------------------------------------------------- 1 | name: docker-image 2 | 3 | on: 4 | push: 5 | branches: [ "stable" ] 6 | paths: 7 | - 'docker/Dockerfile' 8 | pull_request: 9 | branches: [ "stable" ] 10 | paths: 11 | - 'docker/Dockerfile' 12 | 13 | jobs: 14 | 15 | build_and_push: 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | - name: Build the Docker image 23 | run: docker build . --file docker/Dockerfile --tag franckferman/metadetective:1.0.9-df.2 24 | 25 | - name: Login to Docker Hub 26 | run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }} 27 | - name: Push Docker Image 28 | run: docker push franckferman/metadetective:1.0.9-df.2 29 | -------------------------------------------------------------------------------- /.github/workflows/pep8.yml: -------------------------------------------------------------------------------- 1 | name: pep8 2 | 3 | on: 4 | push: 5 | branches: [ "stable" ] 6 | paths: 7 | - 'tests/test_MetaDetective.py' 8 | - 'src/MetaDetective/MetaDetective.py' 9 | pull_request: 10 | branches: [ "stable" ] 11 | paths: 12 | - 'tests/test_MetaDetective.py' 13 | - 'src/MetaDetective/MetaDetective.py' 14 | 15 | jobs: 16 | flake8: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout Repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: 3.11 27 | 28 | - name: Install flake8 29 | run: pip install flake8 30 | 31 | - name: Check PEP8 compliance 32 | run: flake8 . --count --ignore=E501 33 | 34 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: python-publish 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | - name: Set up Python 18 | uses: actions/setup-python@v3 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install build 25 | - name: Build package 26 | run: python -m build 27 | - name: Publish package 28 | uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29 29 | with: 30 | user: __token__ 31 | password: ${{ secrets.PYPI_API_TOKEN }} 32 | 33 | -------------------------------------------------------------------------------- /.github/workflows/static.yml: -------------------------------------------------------------------------------- 1 | name: static 2 | 3 | on: 4 | push: 5 | branches: [ "stable" ] 6 | paths: 7 | - 'docs/website/**' 8 | pull_request: 9 | branches: [ "stable" ] 10 | paths: 11 | - 'docs/website/**' 12 | 13 | # Allows you to run this workflow manually from the Actions tab 14 | workflow_dispatch: 15 | 16 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 17 | permissions: 18 | contents: read 19 | pages: write 20 | id-token: write 21 | 22 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 23 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 24 | concurrency: 25 | group: "pages" 26 | cancel-in-progress: false 27 | 28 | jobs: 29 | # Single deploy job since we're just deploying 30 | deploy: 31 | environment: 32 | name: github-pages 33 | url: ${{ steps.deployment.outputs.page_url }} 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout 37 | uses: actions/checkout@v3 38 | - name: Setup Pages 39 | uses: actions/configure-pages@v3 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@v2 42 | with: 43 | # Upload entire repository 44 | path: './docs/website' 45 | - name: Deploy to GitHub Pages 46 | id: deployment 47 | uses: actions/deploy-pages@v2 48 | -------------------------------------------------------------------------------- /.github/workflows/unittest.yml: -------------------------------------------------------------------------------- 1 | name: unittest 2 | 3 | on: 4 | push: 5 | branches: [ "stable" ] 6 | paths: 7 | - 'tests/test_MetaDetective.py' 8 | - 'src/MetaDetective/MetaDetective.py' 9 | pull_request: 10 | branches: [ "stable" ] 11 | paths: 12 | - 'tests/test_MetaDetective.py' 13 | - 'src/MetaDetective/MetaDetective.py' 14 | 15 | jobs: 16 | unittest: 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout Repository 21 | uses: actions/checkout@v2 22 | 23 | - name: Set up Python 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: 3.11 27 | 28 | - name: Run Unit Tests 29 | run: python -m unittest discover tests -p '*test*.py' 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |

5 | 6 | Sponsored by IPRoyal 7 | 8 |

9 |

This project is supported by IPRoyal
10 | Trusted proxy services for scraping, OSINT and cybersecurity research.

11 | 12 |
13 | 14 | 15 | [![Contributors][contributors-shield]](https://github.com/franckferman/MetaDetective/graphs/contributors) 16 | [![Forks][forks-shield]](https://github.com/franckferman/MetaDetective/network/members) 17 | [![Stargazers][stars-shield]](https://github.com/franckferman/MetaDetective/stargazers) 18 | [![Issues][issues-shield]](https://github.com/franckferman/MetaDetective/issues) 19 | [![License][license-shield]](https://github.com/franckferman/MetaDetective/blob/stable/LICENSE) 20 | 21 | 22 | 23 | MetaDetective Logo 24 | 25 | 26 | 27 |

🕵️‍♂️ MetaDetective

28 |

29 | Unleash Metadata Intelligence with MetaDetective. 30 |
31 | Bridging the chasm in metadata extraction and analysis. 32 |

33 | 34 | 35 |

36 | 📘 Explore the full documentation 37 | · 38 | 🎥 View Demo 39 | · 40 | 🐞 Report Bug 41 | · 42 | 🛠️ Request Feature 43 |

44 | 45 | https://github.com/franckferman/MetaDetective/assets/73023545/7b245f87-37e2-40b7-8b3c-88aefecb4e13 46 | 47 |
48 | 49 | ## 📜 Table of Contents 50 | 51 |
52 | Click to collapse/expand 53 |
    54 |
  1. 📖 About
  2. 55 |
  3. 🛠️ Installation
  4. 56 |
  5. 🎮 Usage
  6. 57 |
  7. ❗ Troubleshooting
  8. 58 |
  9. 🤝 Contributing
  10. 59 |
  11. ⚖️ Legal Disclaimer
  12. 60 |
  13. 🌠 Star Evolution
  14. 61 |
  15. 📜 License
  16. 62 |
  17. 📞 Contact
  18. 63 |
64 |
65 | 66 | ## 📖 About 67 | 68 | **MetaDetective:** _Advanced metadata analysis and web scraping._ 69 | 70 | Metadata, in the realm of cybersecurity, is more than just embedded information; it's a gateway to insightful perspectives, often unveiling crucial leads in OSINT and pentesting. 71 | 72 | As key tools like Metagoofil on Kali Linux shifted their trajectory away from pure metadata analysis, the exigency for a robust alternative took center stage. Enter **MetaDetective**. 73 | 74 | ### 🧠 Tailored Metadata Analysis 75 | 76 | Drawing inspiration from the foundational tools like Metagoofil, MetaDetective emerges as a revitalized and improved iteration, dedicated to providing efficient metadata extraction and presentation. It stands out as a comprehensive Python 3 tool, purposely designed to bridge the existing gaps in metadata analysis. 77 | 78 | ### 📊 Streamlined Data Presentation 79 | 80 | Beyond mere extraction, MetaDetective prides itself on its capability to meticulously categorize and showcase metadata. Whether dealing with an individual file or an array of them, the tool ensures users grasp the entire spectrum of data, both in its breadth and depth. 81 | 82 |

83 | MetaDetective Demo Screenshot 84 |

85 | 86 | ### 🌐 Web Scraping 87 | 88 | While Metagoofil once leaned on Google searches—a method riddled with IP restrictions and the labyrinth of proxy workarounds—MetaDetective pioneers a path with direct web scraping. By targeting sites directly, it sidesteps disruptions, delivering a dataset that's not just richer, but also more precise, spotlighting potential data leaks. 89 | 90 |

91 | MetaDetective Scraping Demo Screenshot 92 |

93 | 94 | ### 🔍 Complementary Utility for OSINT and Pentesting 95 | 96 | Although it is now independent and offers its own functions, including scraping, MetaDetective isn't just a standalone behemoth. It's crafted for seamless integration and synergy with tools like Metagoofil. A quintessential addition to every pentester's and OSINT researcher's toolkit, MetaDetective magnifies data acquisition prowess and broadens the horizons of analysis. 97 | 98 |

(🔼 Back to top)

99 | 100 | ## 🚀 Installation 101 | 102 | Before diving into the installation process, ensure you meet the following prerequisites. 103 | 104 | ### Prerequisites 105 | 106 | 1. **Python 3**: Ensure Python 3 is installed on your system before initiating the installation process. 107 | 108 | 2. **Exiftool**: Given its simplicity, MetaDetective doesn't rely on any external dependencies or libraries. However, it does necessitate exiftool. Ensure you have exiftool set up on your system. 109 | 110 | > ⚠️ **Note**: MetaDetective has been rigorously tested with Python 3.11.4 on Linux alongside exiftool version 12.56. While it may function with other versions, compatibility is guaranteed only with these specific configurations. 111 | 112 | ### Installation methods 113 | 114 | 1. **Git clone the repository**: 115 | ```bash 116 | git clone https://github.com/franckferman/MetaDetective.git 117 | ``` 118 | 119 | 2. **Direct download**: 120 | To skip cloning and directly download the script (designed for simplicity and flexibility, it doesn't depend on any external packages, so if you only need the script, you can also directly download it): 121 | ```bash 122 | curl -O https://raw.githubusercontent.com/franckferman/MetaDetective/stable/src/MetaDetective/MetaDetective.py 123 | ``` 124 | 125 | 3. **Pip Installation**: 126 | 127 | - Create & Activate a Virtual Environment: 128 | ```bash 129 | python3 -m venv MetaDetectiveEnv 130 | source MetaDetectiveEnv/bin/activate 131 | ``` 132 | 133 | - Install MetaDetective: 134 | ```bash 135 | pip install MetaDetective 136 | ``` 137 | 138 | 4. **Docker integration**: 139 | 140 | For a Docker-based setup, refer to our Docker-specific guide: [MetaDetective Docker Setup](https://github.com/franckferman/MetaDetective/blob/stable/docker/README.md). 141 | 142 |

(🔼 Back to top)

143 | 144 | ## 🎮 Usage 145 | 146 | Ensure you adapt your command according to how you've set up `MetaDetective`. 147 | 148 | ### **Getting started** 149 | 150 | Kick off with the built-in help to explore MetaDetective's functionalities: 151 | 152 | ```bash 153 | python3 src/MetaDetective/MetaDetective.py -h 154 | ``` 155 | 156 | ### **Command examples** 157 | 158 | #### 🕵️ File analysis: 159 | 160 | | Task | Command | 161 | | --- | --- | 162 | | Analyze all files in directory | `python3 src/MetaDetective/MetaDetective.py -d examples/` | 163 | | Specific types & ignore patterns | `python3 src/MetaDetective/MetaDetective.py -d examples/ -i ^admin anonymous -t doc pdf` | 164 | | Display all results for each file | `python3 src/MetaDetective/MetaDetective.py -d examples/ -t all --display all` | 165 | 166 | #### 🔎 Export function: 167 | 168 | | Task | Command | 169 | | --- | --- | 170 | | Default export (HTML) | `python3 src/MetaDetective/MetaDetective.py -d examples/ --export` | 171 | | Formatted display, txt export | `python3 src/MetaDetective/MetaDetective.py -d examples ---format formatted -e txt -o ~/` | 172 | 173 | #### 🌐 Web Scraping: 174 | 175 | | Task | Command | 176 | | --- | --- | 177 | | Scan without downloading | `python3 src/MetaDetective/MetaDetective.py --scraping --scan --url https://example.com/` | 178 | | Scan without downloading PDF files only | `python3 src/MetaDetective/MetaDetective.py --scraping --scan --url https://example.com/ --extensions pdf` | 179 | | Download to specified directory | `python3 src/MetaDetective/MetaDetective.py --scraping --download-dir ~ --url https://example.com/` | 180 | | Download with set depth | `python3 src/MetaDetective/MetaDetective.py --scraping --depth 1 --download-dir ~ --url https://example.com/` | 181 | 182 | ### **Additional parameters** 183 | 184 | #### 🌐 Web Scraping: 185 | 186 | To initiate the web scraping mode, use the `--scraping` flag. Remember, this option doesn't function independently. It requires either a scanning or downloading parameter. 187 | 188 | - **Activating web scraping mode**: 189 | ```bash 190 | python3 src/MetaDetective/MetaDetective.py --scraping 191 | ``` 192 | 193 | - **Scanning and displaying statistics**: 194 | Ensure both the URL and `--scan` flags are used. 195 | ```bash 196 | python3 src/MetaDetective/MetaDetective.py --scraping --scan --url https://example.com 197 | ``` 198 | 199 | - **Scans for specific file types and displays related statistics**: 200 | Ensure both the URL and `--scan` flags are used and use `--extensions` followed by a list of desired file types (e.g., pdf docx png). 201 | ```bash 202 | python3 src/MetaDetective/MetaDetective.py --scraping --scan --url https://example.com --extensions pdf docx xlsx pptx 203 | ``` 204 | 205 | - **Downloading web content**: 206 | Indicate the desired directory using `--download-dir` and provide the target URL. 207 | ```bash 208 | python3 src/MetaDetective/MetaDetective.py --scraping --download-dir ~ --url https://example.com 209 | ``` 210 | 211 | - **Downloads web content of specific file types**: 212 | Indicate the desired directory using `--download-dir`, provide the target URL and desired file types with `--extensions`. 213 | ```bash 214 | python3 src/MetaDetective/MetaDetective.py --scraping --download-dir ~ --url https://example.com --extensions pdf docx xlsx pptx 215 | ``` 216 | 217 | - **Adjusting scraping depth**: 218 | Use the `--depth` flag to specify how deeply the scraper should navigate through links. 219 | ```bash 220 | python3 src/MetaDetective/MetaDetective.py --scraping --scan --url https://example.com --depth 1 221 | ``` 222 | 223 | ##### **Additional Flags**: 224 | 225 | - **External link tracking**: 226 | Use `--follow-extern` to allow tracking of external links (those outside the base URL). Typically not advised, but might be useful in certain contexts. 227 | 228 | - **Thread management**: 229 | Use `--threads` to specify the number of threads for concurrent operations. 230 | 231 | - **Rate limiting**: 232 | Use `--rate` to control the maximum number of requests per second. 233 | 234 | #### 🕵️ File analysis & Metadata Analyzer: 235 | 236 | ##### **Basic Commands**: 237 | 238 | To begin analyzing files, you'll use either the `-d` or `-f` flag. 239 | 240 | - `-d` or `--directory`: Select a directory containing one or multiple files. 241 | - `-f` or `--files`: Choose a single or multiple specific files. 242 | 243 | Analyze the contents of a directory. 244 | ```bash 245 | python3 src/MetaDetective/MetaDetective.py -d examples 246 | ``` 247 | 248 | Analyze the contents of a file. 249 | ```bash 250 | python3 src/MetaDetective/MetaDetective.py -f examples/MetaDetective.docx 251 | ``` 252 | 253 | Analyze the contents of multiple files. 254 | ```bash 255 | python3 src/MetaDetective/MetaDetective.py -f examples/MetaDetective-APTX_4869_report.pdf examples/MetaDetective-Kogoro_s_Choice.pdf 256 | ``` 257 | 258 | ##### **Specifying data type** 259 | 260 | You can filter to analyze specific file types: 261 | 262 | | Task | Command | 263 | | --- | --- | 264 | | Specify a data type | `python3 src/MetaDetective/MetaDetective.py -d directory -t pdf` | 265 | | Add multiple data types | `python3 src/MetaDetective/MetaDetective.py -d directory -t pdf doc` | 266 | | Include all types | `python3 src/MetaDetective/MetaDetective.py -d directory -t all` | 267 | 268 | ##### **Ignoring specific results**: 269 | 270 | If you want to omit specific keywords from the displayed metadata, use the `-i` or `--ignore` flag. For instance, you might want to exclude common usernames like "admin" during the reconnaissance phase of your pentest. Regex patterns are supported, e.g., `^BeginBy`. 271 | 272 | | Task | Command | 273 | | --- | --- | 274 | | Exclude specific results | `python3 src/MetaDetective/MetaDetective.py -d directory -i anonymous` | 275 | | Exclude multiple terms | `python3 src/MetaDetective/MetaDetective.py -d directory -i anonymous admin administrateur` | 276 | | Regex exclusions | `python3 src/MetaDetective/MetaDetective.py -d directory -i anonymous ^admin` | 277 | 278 | ##### **Display options** 279 | 280 | Adapt the display of your results to suit your preferences: 281 | 282 | | Task | Command | 283 | | --- | --- | 284 | | Show each file's metadata | `python3 src/MetaDetective/MetaDetective.py --display all` | 285 | | Singular results without duplicates | `python3 src/MetaDetective/MetaDetective.py --display singular` | 286 | 287 | ##### **Format options** 288 | 289 | Modify your display further with these: 290 | 291 | | Task | Command | 292 | | --- | --- | 293 | | Stylish display | `python3 src/MetaDetective/MetaDetective.py --display all --format formatted` | 294 | | Simpler look | `python3 src/MetaDetective/MetaDetective.py --display all --format concise` | 295 | 296 | #### 🔎 **Export options** 297 | 298 | MetaDetective provides flexibility in exporting analysis results. 299 | 300 | By default, using the `--export` or `-e` option will save your results in an HTML format. This design ensures a visually appealing report for your analysis. 301 | 302 | If you prefer a `.txt` format, that's possible too. Switch between formats using the `-e` or `--export` flag followed by the desired format: `-e txt` or `-e pdf`. 303 | 304 | The export will, by default, use a predefined name appended with a timestamp. To customize this name, you can append a suffix using the `-c` or `--custom` flag. 305 | 306 | Further, the `--out` or `-o` argument lets you specify the directory path for your exported data. 307 | 308 | **Be aware**: The `display` and `format` options, as previously discussed, will influence the presentation of your exported document, whether in HTML or TXT format. Data representation might differ between the two formats. 309 | 310 | | Task | Description | Command | 311 | | --- | --- | --- | 312 | | HTML Export (Default) | Produces an HTML file named: `MetaDetective_Export-.html`. | `python3 src/MetaDetective/MetaDetective.py -d directory -e` | 313 | | TXT Format Export | Save results in TXT format. | `python3 src/MetaDetective/MetaDetective.py -d directory --export txt` | 314 | | Custom Filename Suffix | Add a custom suffix to the filename. | `python3 src/MetaDetective/MetaDetective.py -d directory -e --custom Pentest-MD_2` | 315 | | Specify Output Directory | Define the directory for data export. | `python3 src/MetaDetective/MetaDetective.py -d directory -e -o directory` | 316 | 317 |

318 | MetaDetective HTML Export Demo Screenshot 319 |

320 | 321 | **Note**: The export format can greatly affect data presentation and accessibility. Opt for the format that aligns with your requirements. 322 | 323 |

(🔼 Back to top)

324 | 325 | ## 🔧 Troubleshooting 326 | 327 | Encountering issues? Don't worry. If you come across any problems or have questions, please don't hesitate to submit a ticket: [Submit an issue on GitHub](https://github.com/franckferman/MetaDetective/issues) 328 | 329 |

(🔼 Back to top)

330 | 331 | ## 🤝 Contributing 332 | 333 | We truly appreciate and welcome community involvement. Your contributions, feedback, and suggestions play a crucial role in improving the project for everyone. If you're interested in contributing or have ideas for enhancements, please feel free to open an issue or submit a pull request on our GitHub repository. Every contribution, no matter how big or small, is highly valued and greatly appreciated! 334 | 335 |

(🔼 Back to top)

336 | 337 | ## ⚖️ Legal Disclaimer 338 | 339 | Please be aware that the use of the `MetaDetective` tool may be subject to specific laws and regulations in your country or region. Before using this tool, it is your responsibility to ensure that its use is in compliance with the laws applicable in your jurisdiction. 340 | 341 | The creator of `MetaDetective` cannot be held responsible for any improper or illegal use of this tool. By using `MetaDetective`, you acknowledge and agree that you are solely responsible for complying with local laws and regulations. 342 | 343 | In some instances, the use of `MetaDetective` might be justified for legitimate purposes such as protection against authoritarian regimes or for survival matters. However, it is strongly advised to take all necessary measures to protect yourself and to abide by the law. 344 | 345 | By using `MetaDetective`, you acknowledge having read this disclaimer and agree to act accordingly. The creator of `MetaDetective` does not in any way endorse the use of this tool for illegal or harmful purposes. 346 | 347 |

(🔼 Back to top)

348 | 349 | ## 🌠 Star Evolution 350 | 351 | Explore the star history of this project and see how it has evolved over time: 352 | 353 | 354 | 355 | 356 | Star History Chart 357 | 358 | 359 | 360 | Your support is greatly appreciated. We're grateful for every star! Your backing fuels our passion. ✨ 361 | 362 | ## 📚 License 363 | 364 | This project is licensed under the GNU Affero General Public License, Version 3.0. For more details, please refer to the LICENSE file in the repository: [Read the license on GitHub](https://github.com/franckferman/MetaDetective/blob/stable/LICENSE) 365 | 366 |

(🔼 Back to top)

367 | 368 | ## 📞 Contact 369 | 370 | [![ProtonMail][protonmail-shield]](mailto:contact@franckferman.fr) 371 | [![LinkedIn][linkedin-shield]](https://www.linkedin.com/in/franckferman) 372 | [![Twitter][twitter-shield]](https://www.twitter.com/franckferman) 373 | 374 |

(🔼 Back to top)

375 | 376 | 377 | 378 | [contributors-shield]: https://img.shields.io/github/contributors/franckferman/MetaDetective.svg?style=for-the-badge 379 | [contributors-url]: https://github.com/franckferman/MetaDetective/graphs/contributors 380 | [forks-shield]: https://img.shields.io/github/forks/franckferman/MetaDetective.svg?style=for-the-badge 381 | [forks-url]: https://github.com/franckferman/MetaDetective/network/members 382 | [stars-shield]: https://img.shields.io/github/stars/franckferman/MetaDetective.svg?style=for-the-badge 383 | [stars-url]: https://github.com/franckferman/MetaDetective/stargazers 384 | [issues-shield]: https://img.shields.io/github/issues/franckferman/MetaDetective.svg?style=for-the-badge 385 | [issues-url]: https://github.com/franckferman/MetaDetective/issues 386 | [license-shield]: https://img.shields.io/github/license/franckferman/MetaDetective.svg?style=for-the-badge 387 | [license-url]: https://github.com/franckferman/MetaDetective/blob/stable/LICENSE 388 | [protonmail-shield]: https://img.shields.io/badge/ProtonMail-8B89CC?style=for-the-badge&logo=protonmail&logoColor=blueviolet 389 | [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=blue 390 | [twitter-shield]: https://img.shields.io/badge/-Twitter-black.svg?style=for-the-badge&logo=twitter&colorB=blue 391 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | ## TODO 2 | 3 | ### Metadata enhancements 4 | 5 | - [X] ~~**GPS and photo metadata improvements**~~ 6 | - [X] ~~Add missing metadata fields, especially for geolocation, camera model name, and other device-specific information for images.~~ 7 | - [X] ~~Develop a function to convert GPS data to OSM or Google Maps links.~~ 8 | 9 | ### Data export features 10 | 11 | - [X] ~~**Support various export formats**~~ 12 | - [X] ~~Added support for exporting data in HTML format.~~ 13 | - [X] ~~Added support for exporting data in TXT format.~~ 14 | - [X] ~~Implement customizable export options for users.~~ 15 | - [X] ~~Implement advanced customizable export options for users.~~ 16 | 17 | ### GitHub Actions 18 | 19 | - [X] ~~**PyPI Automatic Upload on Release**~~ 20 | - [X] ~~Integrate GitHub Actions to trigger PyPI package upload on every new release.~~ 21 | 22 | ### Advanced Filtering 23 | 24 | - [ ] **Enhanced Filtering Capabilities** 25 | - [X] ~~Add support for scraping filter options.~~ 26 | - [ ] Implement local filtering based on sections like "Author" and "Last Modified By". 27 | 28 | ### Performance Enhancements 29 | 30 | - [ ] **Optimize File Comparison for Duplication Avoidance** 31 | - [ ] Replace SHA256 hash verification with a less resource-intensive method. 32 | - [ ] Research and evaluate the use of CRC32, or equivalent alternatives, for quick file comparison. 33 | - [ ] Implement CRC32 or chosen alternative for file integrity checks aimed at duplication avoidance rather than secure cryptographic verification. 34 | 35 | ### Website Enhancement 36 | 37 | - [ ] **Incorporate Metadata Example Files** 38 | - [ ] Host a set of diverse example files embedded with metadata on the MetaDetective site. 39 | - [ ] Ensure these example files cover a wide range of metadata scenarios to showcase MetaDetective’s capabilities. 40 | - [ ] Replace references to "https://example.com" in documentation and demos with links to these metadata example files on the MetaDetective site. 41 | - [ ] Update documentation and tutorials to direct users to these specific examples for more relevant and practical demonstrations of MetaDetective's functionalities. 42 | 43 | ### Functionalities for Parsing 44 | 45 | - [ ] **Advanced Parsing Features** 46 | - [ ] Implement parsing options to selectively export specific attributes in a format usable by other tools. 47 | - [ ] Enable parsing for simplified export and integration with other tools or databases. 48 | - [ ] Include options for automatic modification and enrichment of data. 49 | - [ ] Develop feature to automatically append email aliases (domain names) to usernames. 50 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:bullseye-slim 2 | 3 | LABEL maintainer="Franck FERMAN " \ 4 | description="Unleash Metadata Intelligence with MetaDetective." \ 5 | metadetective_version="1.0.9" \ 6 | docker_image_version="1.0.2" 7 | 8 | RUN apt-get update && \ 9 | apt-get install -y \ 10 | python3 \ 11 | python3-pip \ 12 | libimage-exiftool-perl \ 13 | --no-install-recommends && \ 14 | rm -rf /var/lib/apt/lists/* 15 | 16 | RUN pip3 install MetaDetective && \ 17 | rm -rf ~/.cache/pip 18 | 19 | ENV PATH="/root/.local/bin:${PATH}" 20 | 21 | CMD ["tail", "-f", "/dev/null"] 22 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # MetaDetective Docker Setup 2 | 3 | This document offers instructions on how to set up and utilize the Dockerized version of MetaDetective. 4 | 5 | ## Table of Contents 6 | 7 |
8 | Table of Contents 9 |
    10 |
  1. Getting Started
  2. 11 |
  3. Using the Pre-built Image
  4. 12 |
  5. Dockerfile Details
  6. 13 |
14 |
15 | 16 | ## Getting Started 17 | 18 | ### Prerequisites 19 | 20 | - Docker must be installed on your machine. 21 | - While the Docker image can technically be run on Windows, the provided scripts are written in Bash. Thus, they are designed for environments that support Bash scripting, like Linux. 22 | 23 |

(🔼 Back to top)

24 | 25 | ### Building the Docker Image 26 | 27 | To build and run the Docker image: 28 | ```bash 29 | # ./start.sh 30 | ``` 31 | 32 | When executed, this script performs the following actions: 33 | 1. It checks if the metadetective-image already exists. If it doesn't, the script builds one using the provided Dockerfile. 34 | 2. It runs a container named metadetective-container. 35 | 3. Upon completion, you'll be placed inside the container shell, where you're ready to start using MetaDetective. 36 |

(🔼 Back to top)

37 | 38 | ### Stopping and Removing Containers and Images 39 | 40 | In case you want to stop the running container and/or remove the Docker image: 41 | ```bash 42 | # ./remove.sh 43 | ``` 44 | 45 | Executing this script will: 46 | 1. Stop and remove the metadetective-container if it's currently running. 47 | 2. Prompt you with the option to delete the metadetective-image. 48 | 49 |

(🔼 Back to top)

50 | 51 | ## Using the Pre-built Image 52 | 53 | If you'd rather use the pre-built Docker image from Docker Hub, follow these steps: 54 | 55 | ### Pulling the Image 56 | 57 | Retrieve the Docker image using: 58 | ```bash 59 | # docker pull franckferman/metadetective 60 | ``` 61 | 62 | ### Running the Container 63 | 64 | Start a container based on the image: 65 | ```bash 66 | # docker run -it --name metadetective franckferman/metadetective /bin/bash 67 | ``` 68 | 69 | ### Stopping the Container 70 | 71 | ```bash 72 | # docker stop metadetective 73 | ``` 74 | 75 | This command will stop the container named "metadetective". 76 | 77 | ### Removing the Container 78 | 79 | Once the container is stopped, you can remove it using: 80 | ```bash 81 | # docker rm metadetective 82 | ``` 83 | 84 | This command will remove the container named "metadetective". 85 | 86 | ### Troubleshooting container deletion problems 87 | 88 | 1. List All Containers (including stopped ones): 89 | ```bash 90 | # docker ps -a 91 | ``` 92 | 93 | Check if the container "metadetective" is listed. If it's listed, note the container ID. 94 | 95 | 2. Force Remove the Container: 96 | ```bash 97 | # docker rm -f metadetective 98 | ``` 99 | 100 | Alternatively, if using the container ID: 101 | ```bash 102 | # docker rm -f [CONTAINER_ID] 103 | ``` 104 | 105 |

(🔼 Back to top)

106 | 107 | ## Dockerfile Details 108 | 109 | Our Docker image is built upon the lightweight foundation of `debian:bullseye-slim`. 110 | 111 | The following essential packages are installed: 112 | 113 | `python3`: The core programming language for running MetaDetective. 114 | 115 | `python3-pip`: Used specifically to fetch and install the MetaDetective release directly from PyPI. 116 | 117 | `libimage-exiftool-perl`: MetaDetective partly relies on this tool for metadata extraction and analysis. 118 | 119 | Due to the ENV PATH="/root/.local/bin:${PATH}" setting in the Dockerfile, you can directly launch MetaDetective within the container without needing to navigate to any specific directory. Simply invoke MetaDetective followed by the desired command-line arguments. 120 | 121 |

(🔼 Back to top)

122 | -------------------------------------------------------------------------------- /docker/remove.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | IMAGE_NAME="metadetective-image" 4 | CONTAINER_NAME="metadetective-container" 5 | 6 | # Check if container is running 7 | CONTAINER_ID=$(sudo docker ps -aqf "name=$CONTAINER_NAME" -q) 8 | 9 | if [ ! -z "$CONTAINER_ID" ]; then 10 | echo "Stopping and removing the $CONTAINER_NAME container..." 11 | if ! sudo docker rm -f $CONTAINER_ID; then 12 | echo "Error removing container $CONTAINER_NAME." >&2 13 | exit 1 14 | fi 15 | else 16 | echo "No container found: $CONTAINER_NAME" 17 | fi 18 | 19 | # Check if image exists 20 | IMAGE_EXISTS=$(sudo docker images -q $IMAGE_NAME) 21 | 22 | if [ ! -z "$IMAGE_EXISTS" ]; then 23 | read -p "Do you also want to delete the Docker image ($IMAGE_NAME)? [y/N] " response 24 | if [[ "$response" =~ ^([yY][eE][sS]|[yY])$ ]]; then 25 | if ! sudo docker rmi $IMAGE_EXISTS; then 26 | echo "Error deleting Docker image $IMAGE_NAME." >&2 27 | exit 1 28 | fi 29 | echo "Docker image $IMAGE_NAME deleted." 30 | fi 31 | else 32 | echo "No Docker image found: $IMAGE_NAME" 33 | fi 34 | 35 | -------------------------------------------------------------------------------- /docker/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | IMAGE_NAME="metadetective-image" 4 | CONTAINER_NAME="metadetective-container" 5 | 6 | # Check if image exists 7 | IMAGE_EXISTS=$(sudo docker images -q $IMAGE_NAME) 8 | 9 | if [ -z "$IMAGE_EXISTS" ]; then 10 | echo "Building Docker image..." 11 | if ! sudo docker build -t $IMAGE_NAME .; then 12 | echo "Error building Docker image." >&2 13 | exit 1 14 | fi 15 | else 16 | echo "Using existing Docker image..." 17 | fi 18 | 19 | # Check if container is running 20 | CONTAINER_ID=$(sudo docker ps -aqf "name=$CONTAINER_NAME") 21 | 22 | if [ ! -z "$CONTAINER_ID" ]; then 23 | echo "Stopping existing container..." 24 | sudo docker stop $CONTAINER_NAME 25 | echo "Removing existing container..." 26 | sudo docker rm $CONTAINER_NAME 27 | fi 28 | 29 | # Run the container 30 | echo "Running new container..." 31 | if ! sudo docker run -d --rm --name $CONTAINER_NAME $IMAGE_NAME; then 32 | echo "Error running container." >&2 33 | exit 1 34 | fi 35 | 36 | # Enter the container shell 37 | echo "Entering container shell..." 38 | sudo docker exec -it $CONTAINER_NAME /bin/bash 39 | 40 | -------------------------------------------------------------------------------- /docs/github/graphical_resources/IPRoyal-Logo_Transparent_500x500.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/IPRoyal-Logo_Transparent_500x500.png -------------------------------------------------------------------------------- /docs/github/graphical_resources/Logo-Without_background-MetaDetective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/Logo-Without_background-MetaDetective.png -------------------------------------------------------------------------------- /docs/github/graphical_resources/Logo-Without_background-Without_text-MetaDetective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/Logo-Without_background-Without_text-MetaDetective.png -------------------------------------------------------------------------------- /docs/github/graphical_resources/MetaDetective_promotional_trailer.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/MetaDetective_promotional_trailer.mp4 -------------------------------------------------------------------------------- /docs/github/graphical_resources/Screenshot-MetaDetective_Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/Screenshot-MetaDetective_Demo.png -------------------------------------------------------------------------------- /docs/github/graphical_resources/Screenshot-MetaDetective_HTML_Export_Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/Screenshot-MetaDetective_HTML_Export_Demo.png -------------------------------------------------------------------------------- /docs/github/graphical_resources/Screenshot-MetaDetective_Scraping_Demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/github/graphical_resources/Screenshot-MetaDetective_Scraping_Demo.png -------------------------------------------------------------------------------- /docs/website/css/base.css: -------------------------------------------------------------------------------- 1 | /** 2 | * =================================================================== 3 | * 4 | * MetaDetective Base Stylesheet 5 | * url: franckferman.github.io/MetaDetective 6 | * created: 27-10-2023 7 | * 8 | * =================================================================== 9 | */ 10 | 11 | /** 12 | * =================================================================== 13 | * reset - normalize.css v3.0.2 | MIT License | git.io/normalize 14 | * 15 | * ------------------------------------------------------------------- 16 | */ 17 | 18 | html { 19 | font-family: sans-serif; 20 | -ms-text-size-adjust: 100%; 21 | -webkit-text-size-adjust: 100%; 22 | } 23 | body { 24 | margin: 0; 25 | } 26 | article, 27 | aside, 28 | details, 29 | figcaption, 30 | figure, 31 | footer, 32 | header, 33 | hgroup, 34 | main, 35 | menu, 36 | nav, 37 | section, 38 | summary { 39 | display: block; 40 | } 41 | audio, canvas, progress, video { 42 | display: inline-block; 43 | vertical-align: baseline; 44 | } 45 | audio:not([controls]) { 46 | display: none; 47 | height: 0; 48 | } 49 | [hidden], template { 50 | display: none; 51 | } 52 | a { 53 | background: transparent; 54 | } 55 | a:active, a:hover { 56 | outline: 0; 57 | } 58 | abbr[title] { 59 | border-bottom: 1px dotted; 60 | } 61 | b, strong { 62 | font-weight: bold; 63 | } 64 | dfn { 65 | font-style: italic; 66 | } 67 | h1 { 68 | font-size: 2em; 69 | margin: 0.67em 0; 70 | } 71 | mark { 72 | background: #ff0; 73 | color: #000; 74 | } 75 | small { 76 | font-size: 80%; 77 | } 78 | sub, sup { 79 | font-size: 75%; 80 | line-height: 0; 81 | position: relative; 82 | vertical-align: baseline; 83 | } 84 | sup { 85 | top: -0.5em; 86 | } 87 | sub { 88 | bottom: -0.25em; 89 | } 90 | img { 91 | border: 0; 92 | } 93 | svg:not(:root) { 94 | overflow: hidden; 95 | } 96 | figure { 97 | margin: 1em 40px; 98 | } 99 | hr { 100 | -moz-box-sizing: content-box; 101 | box-sizing: content-box; 102 | height: 0; 103 | } 104 | pre { 105 | overflow: auto; 106 | } 107 | code, kbd, pre, samp { 108 | font-family: monospace, monospace; 109 | font-size: 1em; 110 | } 111 | button, input, optgroup, select, textarea { 112 | color: inherit; 113 | font: inherit; 114 | margin: 0; 115 | } 116 | button { 117 | overflow: visible; 118 | } 119 | button, select { 120 | text-transform: none; 121 | } 122 | button, 123 | html input[type="button"], 124 | input[type="reset"], 125 | input[type="submit"] { 126 | -webkit-appearance: button; 127 | cursor: pointer; 128 | } 129 | button[disabled], html input[disabled] { 130 | cursor: default; 131 | } 132 | button::-moz-focus-inner, input::-moz-focus-inner { 133 | border: 0; 134 | padding: 0; 135 | } 136 | input { 137 | line-height: normal; 138 | } 139 | input[type="checkbox"], input[type="radio"] { 140 | box-sizing: border-box; 141 | padding: 0; 142 | } 143 | input[type="number"]::-webkit-inner-spin-button, 144 | input[type="number"]::-webkit-outer-spin-button { 145 | height: auto; 146 | } 147 | input[type="search"] { 148 | -webkit-appearance: textfield; 149 | -moz-box-sizing: content-box; 150 | -webkit-box-sizing: content-box; 151 | box-sizing: content-box; 152 | } 153 | input[type="search"]::-webkit-search-cancel-button, 154 | input[type="search"]::-webkit-search-decoration { 155 | -webkit-appearance: none; 156 | } 157 | fieldset { 158 | border: 1px solid #c0c0c0; 159 | margin: 0 2px; 160 | padding: 0.35em 0.625em 0.75em; 161 | } 162 | legend { 163 | border: 0; 164 | padding: 0; 165 | } 166 | textarea { 167 | overflow: auto; 168 | } 169 | optgroup { 170 | font-weight: bold; 171 | } 172 | table { 173 | border-collapse: collapse; 174 | border-spacing: 0; 175 | } 176 | td, th { 177 | padding: 0; 178 | } 179 | 180 | /** 181 | * =================================================================== 182 | * basic/base setup styles 183 | * 184 | * ------------------------------------------------------------------- 185 | */ 186 | 187 | html { 188 | font-size: 62.5%; 189 | box-sizing: border-box; 190 | } 191 | *, *::before, *::after { 192 | box-sizing: inherit; 193 | } 194 | body { 195 | font-weight: normal; 196 | line-height: 1; 197 | text-rendering: optimizeLegibility; 198 | word-wrap: break-word; 199 | -webkit-overflow-scrolling: touch; 200 | -webkit-text-size-adjust: none; 201 | } 202 | body, input, button { 203 | -moz-osx-font-smoothing: grayscale; 204 | -webkit-font-smoothing: antialiased; 205 | } 206 | 207 | /** 208 | * Media 209 | * - 210 | */ 211 | 212 | img, video { 213 | max-width: 100%; 214 | height: auto; 215 | } 216 | 217 | /** 218 | * Typography resets 219 | * - 220 | */ 221 | 222 | div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { 223 | margin: 0; 224 | padding: 0; 225 | } 226 | h1, h2, h3, h4, h5, h6 { 227 | -webkit-font-variant-ligatures: common-ligatures; 228 | -moz-font-variant-ligatures: common-ligatures; 229 | font-variant-ligatures: common-ligatures; 230 | text-rendering: optimizeLegibility; 231 | } 232 | em, i { 233 | font-style: italic; 234 | line-height: inherit; 235 | } 236 | strong, b { 237 | font-weight: bold; 238 | line-height: inherit; 239 | } 240 | small { 241 | font-size: 60%; 242 | line-height: inherit; 243 | } 244 | ol, ul { 245 | list-style: none; 246 | } 247 | li { 248 | display: block; 249 | } 250 | 251 | /** 252 | * links 253 | * - 254 | */ 255 | 256 | a { 257 | text-decoration: none; 258 | line-height: inherit; 259 | } 260 | a img { 261 | border: none; 262 | } 263 | 264 | /** 265 | * inputs 266 | * - 267 | */ 268 | 269 | fieldset { 270 | margin: 0; 271 | padding: 0; 272 | } 273 | input[type="email"], 274 | input[type="number"], 275 | input[type="search"], 276 | input[type="text"], 277 | input[type="tel"], 278 | input[type="url"], 279 | input[type="password"], 280 | textarea { 281 | -webkit-appearance: none; 282 | -moz-appearance: none; 283 | -ms-appearance: none; 284 | -o-appearance: none; 285 | appearance: none; 286 | } 287 | 288 | /** 289 | * =================================================================== 290 | * grid 291 | * 292 | * ------------------------------------------------------------------- 293 | */ 294 | 295 | .row { 296 | width: 94%; 297 | max-width: 1140px; 298 | margin: 0 auto; 299 | } 300 | .row:before, .row:after { 301 | content: ""; 302 | display: table; 303 | } 304 | .row:after { 305 | clear: both; 306 | } 307 | .row .row { 308 | width: auto; 309 | max-width: none; 310 | margin-left: -20px; 311 | margin-right: -20px; 312 | } 313 | [class*="col-"], .bgrid { 314 | float: left; 315 | } 316 | [class*="col-"] + [class*="col-"]:last-child { 317 | float: right; 318 | } 319 | [class*="col-"] { 320 | padding: 0 20px; 321 | } 322 | .col-one { 323 | width: 8.33333%; 324 | } 325 | .col-two, .col-1-6 { 326 | width: 16.66667%; 327 | } 328 | .col-three, .col-1-4 { 329 | width: 25%; 330 | } 331 | .col-four, .col-1-3 { 332 | width: 33.33333%; 333 | } 334 | .col-five { 335 | width: 41.66667%; 336 | } 337 | .col-six, .col-1-2 { 338 | width: 50%; 339 | } 340 | .col-seven { 341 | width: 58.33333%; 342 | } 343 | .col-eight, .col-2-3 { 344 | width: 66.66667%; 345 | } 346 | .col-nine, .col-3-4 { 347 | width: 75%; 348 | } 349 | .col-ten, .col-5-6 { 350 | width: 83.33333%; 351 | } 352 | .col-eleven { 353 | width: 91.66667%; 354 | } 355 | .col-twelve, .col-full { 356 | width: 100%; 357 | } 358 | 359 | /** 360 | * small screens 361 | * --------------------------------------------------------------- 362 | */ 363 | 364 | @media screen and (max-width:1024px) { 365 | .row .row { 366 | margin-left: -18px; 367 | margin-right: -18px; 368 | } 369 | [class*="col-"] { 370 | padding: 0 18px; 371 | } 372 | } 373 | 374 | /** 375 | * tablets 376 | * --------------------------------------------------------------- 377 | */ 378 | 379 | @media screen and (max-width:768px) { 380 | .row { 381 | width: auto; 382 | padding-left: 30px; 383 | padding-right: 30px; 384 | } 385 | .row .row { 386 | padding-left: 0; 387 | padding-right: 0; 388 | margin-left: -15px; 389 | margin-right: -15px; 390 | } 391 | [class*="col-"] { 392 | padding: 0 15px; 393 | } 394 | .tab-1-4 { 395 | width: 25%; 396 | } 397 | .tab-1-3 { 398 | width: 33.33333%; 399 | } 400 | .tab-1-2 { 401 | width: 50%; 402 | } 403 | .tab-2-3 { 404 | width: 66.66667%; 405 | } 406 | .tab-3-4 { 407 | width: 75%; 408 | } 409 | .tab-full { 410 | width: 100%; 411 | } 412 | } 413 | 414 | /** 415 | * large mobile devices 416 | * --------------------------------------------------------------- 417 | */ 418 | 419 | @media screen and (max-width:600px) { 420 | .row { 421 | padding-left: 25px; 422 | padding-right: 25px; 423 | } 424 | .row .row { 425 | margin-left: -10px; 426 | margin-right: -10px; 427 | } 428 | [class*="col-"] { 429 | padding: 0 10px; 430 | } 431 | .mob-1-4 { 432 | width: 25%; 433 | } 434 | .mob-1-2 { 435 | width: 50%; 436 | } 437 | .mob-3-4 { 438 | width: 75%; 439 | } 440 | .mob-full { 441 | width: 100%; 442 | } 443 | } 444 | 445 | /** 446 | * small mobile devices 447 | * --------------------------------------------------------------- 448 | */ 449 | 450 | @media screen and (max-width:400px) { 451 | .row { 452 | padding-left: 30px; 453 | padding-right: 30px; 454 | } 455 | .row .row { 456 | padding-left: 0; 457 | padding-right: 0; 458 | margin-left: 0; 459 | margin-right: 0; 460 | } 461 | [class*="col-"] { 462 | width: 100% !important; 463 | float: none !important; 464 | clear: both !important; 465 | margin-left: 0; 466 | margin-right: 0; 467 | padding: 0; 468 | } 469 | [class*="col-"] + [class*="col-"]:last-child { 470 | float: none; 471 | } 472 | } 473 | 474 | /** 475 | * =================================================================== 476 | * block grids 477 | * 478 | * ------------------------------------------------------------------- 479 | */ 480 | 481 | .block-1-6 .bgrid { 482 | width: 16.66667%; 483 | } 484 | .block-1-4 .bgrid { 485 | width: 25%; 486 | } 487 | .block-1-3 .bgrid { 488 | width: 33.33333%; 489 | } 490 | .block-1-2 .bgrid { 491 | width: 50%; 492 | } 493 | 494 | /** 495 | * Clearing for block grid columns. Allow columns with 496 | * different heights to align properly. 497 | */ 498 | 499 | .block-1-6 .bgrid:nth-child(6n+1), 500 | .block-1-4 .bgrid:nth-child(4n+1), 501 | .block-1-3 .bgrid:nth-child(3n+1), 502 | .block-1-2 .bgrid:nth-child(2n+1) { 503 | clear: both; 504 | } 505 | 506 | /** 507 | * small screens 508 | * --------------------------------------------------------------- 509 | */ 510 | @media screen and (max-width:1024px) { 511 | .block-s-1-6 .bgrid { 512 | width: 16.66667%; 513 | } 514 | .block-s-1-4 .bgrid { 515 | width: 25%; 516 | } 517 | .block-s-1-3 .bgrid { 518 | width: 33.33333%; 519 | } 520 | .block-s-1-2 .bgrid { 521 | width: 50%; 522 | } 523 | .block-s-full .bgrid { 524 | width: 100%; 525 | clear: both; 526 | } 527 | [class*="block-s-"] .bgrid:nth-child(n) { 528 | clear: none; 529 | } 530 | .block-s-1-6 .bgrid:nth-child(6n+1), 531 | .block-s-1-4 .bgrid:nth-child(4n+1), 532 | .block-s-1-3 .bgrid:nth-child(3n+1), 533 | .block-s-1-2 .bgrid:nth-child(2n+1) { 534 | clear: both; 535 | } 536 | } 537 | 538 | /** 539 | * tablets 540 | * --------------------------------------------------------------- 541 | */ 542 | @media screen and (max-width:768px) { 543 | .block-tab-1-6 .bgrid { 544 | width: 16.66667%; 545 | } 546 | .block-tab-1-4 .bgrid { 547 | width: 25%; 548 | } 549 | .block-tab-1-3 .bgrid { 550 | width: 33.33333%; 551 | } 552 | .block-tab-1-2 .bgrid { 553 | width: 50%; 554 | } 555 | .block-tab-full .bgrid { 556 | width: 100%; 557 | clear: both; 558 | } 559 | [class*="tab-bgrid-"] .bgrid:nth-child(n) { 560 | clear: none; 561 | } 562 | .block-tab-1-6 .bgrid:nth-child(6n+1), 563 | .block-tab-1-4 .bgrid:nth-child(4n+1), 564 | .block-tab-1-3 .bgrid:nth-child(3n+1), 565 | .block-tab-1-2 .bgrid:nth-child(2n+1) { 566 | clear: both; 567 | } 568 | } 569 | 570 | /** 571 | * mobile devices 572 | * --------------------------------------------------------------- 573 | */ 574 | @media screen and (max-width:600px) { 575 | .block-mob-1-6 .bgrid { 576 | width: 16.66667%; 577 | } 578 | .block-mob-1-4 .bgrid { 579 | width: 25%; 580 | } 581 | .block-mob-1-3 .bgrid { 582 | width: 33.33333%; 583 | } 584 | .block-mob-1-2 .bgrid { 585 | width: 50%; 586 | } 587 | .block-mob-full .bgrid { 588 | width: 100%; 589 | clear: both; 590 | } 591 | [class*="mob-bgrid-"] .bgrid:nth-child(n) { 592 | clear: none; 593 | } 594 | .block-mob-1-6 .bgrid:nth-child(6n+1), 595 | .block-mob-1-4 .bgrid:nth-child(4n+1), 596 | .block-mob-1-3 .bgrid:nth-child(3n+1), 597 | .block-mob-1-2 .bgrid:nth-child(2n+1) { 598 | clear: both; 599 | } 600 | } 601 | 602 | /** 603 | * stack on small mobile devices 604 | * --------------------------------------------------------------- 605 | */ 606 | 607 | @media screen and (max-width:400px) { 608 | .stack .bgrid { 609 | width: 100% !important; 610 | float: none !important; 611 | clear: both !important; 612 | margin-left: 0; 613 | margin-right: 0; 614 | } 615 | } 616 | 617 | /** 618 | * =================================================================== 619 | * MISC 620 | * 621 | * ------------------------------------------------------------------- 622 | */ 623 | 624 | /** 625 | * Clearing - (http://nicolasgallagher.com/micro-clearfix-hack/ 626 | * - 627 | */ 628 | 629 | .group:before, .group:after { 630 | content: ""; 631 | display: table; 632 | } 633 | .group:after { 634 | clear: both; 635 | } 636 | 637 | /** 638 | * Misc Helper Styles 639 | * - 640 | */ 641 | 642 | .hide { display: none; } 643 | .invisible { visibility: hidden; } 644 | .antialiased { 645 | -webkit-font-smoothing: antialiased; 646 | -moz-osx-font-smoothing: grayscale; 647 | } 648 | .remove-bottom { margin-bottom: 0; } 649 | .half-bottom { margin-bottom: 1.5rem !important; } 650 | .add-bottom { margin-bottom: 3rem !important; } 651 | .no-border { border: none; } 652 | .full-width { width: 100%; } 653 | .text-center { text-align: center; } 654 | .text-left { text-align: left; } 655 | .text-right { text-align: right; } 656 | .pull-left { float: left; } 657 | .pull-right { float: right; } 658 | .align-center { 659 | margin-left: auto; 660 | margin-right: auto; 661 | text-align: center; 662 | } 663 | 664 | /*# sourceMappingURL=base.css.map */ 665 | -------------------------------------------------------------------------------- /docs/website/css/fonts.css: -------------------------------------------------------------------------------- 1 | /* Generated by Font Squirrel (http://www.fontsquirrel.com) */ 2 | 3 | /* 4 | * Montserrat 5 | ================================================================================ */ 6 | 7 | @font-face { 8 | font-family: 'montserrat-regular'; 9 | src: url('../fonts/montserrat/montserrat-regular-webfont.eot'); 10 | src: url('../fonts/montserrat/montserrat-regular-webfont.eot?#iefix') format('embedded-opentype'), 11 | url('../fonts/montserrat/montserrat-regular-webfont.woff') format('woff'), 12 | url('../fonts/montserrat/montserrat-regular-webfont.ttf') format('truetype'), 13 | url('../fonts/montserrat/montserrat-regular-webfont.svg#montserratregular') format('svg'); 14 | font-weight: normal; 15 | font-style: normal; 16 | } 17 | @font-face { 18 | font-family: 'montserrat-bold'; 19 | src: url('../fonts/montserrat/montserrat-bold-webfont.eot'); 20 | src: url('../fonts/montserrat/montserrat-bold-webfont.eot?#iefix') format('embedded-opentype'), 21 | url('../fonts/montserrat/montserrat-bold-webfont.woff') format('woff'), 22 | url('../fonts/montserrat/montserrat-bold-webfont.ttf') format('truetype'), 23 | url('../fonts/montserrat/montserrat-bold-webfont.svg#montserratbold') format('svg'); 24 | font-weight: normal; 25 | font-style: normal; 26 | } 27 | 28 | /* 29 | * Raleway 30 | ================================================================================ */ 31 | @font-face { 32 | font-family: 'raleway-thin'; 33 | src: url('../fonts/raleway/raleway-thin-webfont.eot'); 34 | src: url('../fonts/raleway/raleway-thin-webfont.eot?#iefix') format('embedded-opentype'), 35 | url('../fonts/raleway/raleway-thin-webfont.woff') format('woff'), 36 | url('../fonts/raleway/raleway-thin-webfont.ttf') format('truetype'), 37 | url('../fonts/raleway/raleway-thin-webfont.svg#ralewaythin') format('svg'); 38 | font-weight: normal; 39 | font-style: normal; 40 | } 41 | @font-face { 42 | font-family: 'raleway-extra-light'; 43 | src: url('../fonts/raleway/raleway-extralight-webfont.eot'); 44 | src: url('../fonts/raleway/raleway-extralight-webfont.eot?#iefix') format('embedded-opentype'), 45 | url('../fonts/raleway/raleway-extralight-webfont.woff') format('woff'), 46 | url('../fonts/raleway/raleway-extralight-webfont.ttf') format('truetype'), 47 | url('../fonts/raleway/raleway-extralight-webfont.svg#ralewayextralight') format('svg'); 48 | font-weight: normal; 49 | font-style: normal; 50 | } 51 | @font-face { 52 | font-family: 'raleway-light'; 53 | src: url('../fonts/raleway/raleway-light-webfont.eot'); 54 | src: url('../fonts/raleway/raleway-light-webfont.eot?#iefix') format('embedded-opentype'), 55 | url('../fonts/raleway/raleway-light-webfont.woff') format('woff'), 56 | url('../fonts/raleway/raleway-light-webfont.ttf') format('truetype'), 57 | url('../fonts/raleway/raleway-light-webfont.svg#ralewaylight') format('svg'); 58 | font-weight: normal; 59 | font-style: normal; 60 | } 61 | @font-face { 62 | font-family: 'raleway-regular'; 63 | src: url('../fonts/raleway/raleway-regular-webfont.eot'); 64 | src: url('../fonts/raleway/raleway-regular-webfont.eot?#iefix') format('embedded-opentype'), 65 | url('../fonts/raleway/raleway-regular-webfont.woff') format('woff'), 66 | url('../fonts/raleway/raleway-regular-webfont.ttf') format('truetype'), 67 | url('../fonts/raleway/raleway-regular-webfont.svg#ralewayregular') format('svg'); 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | @font-face { 72 | font-family: 'raleway-medium'; 73 | src: url('../fonts/raleway/raleway-medium-webfont.eot'); 74 | src: url('../fonts/raleway/raleway-medium-webfont.eot?#iefix') format('embedded-opentype'), 75 | url('../fonts/raleway/raleway-medium-webfont.woff') format('woff'), 76 | url('../fonts/raleway/raleway-medium-webfont.ttf') format('truetype'), 77 | url('../fonts/raleway/raleway-medium-webfont.svg#ralewaymedium') format('svg'); 78 | font-weight: normal; 79 | font-style: normal; 80 | } 81 | @font-face { 82 | font-family: 'raleway-semibold'; 83 | src: url('../fonts/raleway/raleway-semibold-webfont.eot'); 84 | src: url('../fonts/raleway/raleway-semibold-webfont.eot?#iefix') format('embedded-opentype'), 85 | url('../fonts/raleway/raleway-semibold-webfont.woff') format('woff'), 86 | url('../fonts/raleway/raleway-semibold-webfont.ttf') format('truetype'), 87 | url('../fonts/raleway/raleway-semibold-webfont.svg#ralewaysemibold') format('svg'); 88 | font-weight: normal; 89 | font-style: normal; 90 | } 91 | @font-face { 92 | font-family: 'raleway-bold'; 93 | src: url('../fonts/raleway/raleway-bold-webfont.eot'); 94 | src: url('../fonts/raleway/raleway-bold-webfont.eot?#iefix') format('embedded-opentype'), 95 | url('../fonts/raleway/raleway-bold-webfont.woff') format('woff'), 96 | url('../fonts/raleway/raleway-bold-webfont.ttf') format('truetype'), 97 | url('../fonts/raleway/raleway-bold-webfont.svg#ralewaybold') format('svg'); 98 | font-weight: normal; 99 | font-style: normal; 100 | } 101 | @font-face { 102 | font-family: 'raleway-heavy'; 103 | src: url('../fonts/raleway/raleway-heavy-webfont.eot'); 104 | src: url('../fonts/raleway/raleway-heavy-webfont.eot?#iefix') format('embedded-opentype'), 105 | url('../fonts/raleway/raleway-heavy-webfont.woff') format('woff'), 106 | url('../fonts/raleway/raleway-heavy-webfont.ttf') format('truetype'), 107 | url('../fonts/raleway/raleway-heavy-webfont.svg#ralewayheavy') format('svg'); 108 | font-weight: normal; 109 | font-style: normal; 110 | } 111 | 112 | /* 113 | * Merriweather 114 | ================================================================================ */ 115 | 116 | @font-face { 117 | font-family: 'merriweather-heavy'; 118 | src: url('../fonts/merriweather/merriweather-black-webfont.eot'); 119 | src: url('../fonts/merriweather/merriweather-black-webfont.eot?#iefix') format('embedded-opentype'), 120 | url('../fonts/merriweather/merriweather-black-webfont.woff') format('woff'), 121 | url('../fonts/merriweather/merriweather-black-webfont.ttf') format('truetype'), 122 | url('../fonts/merriweather/merriweather-black-webfont.svg#merriweatherheavy') format('svg'); 123 | font-weight: normal; 124 | font-style: normal; 125 | } 126 | @font-face { 127 | font-family: 'merriweather-bold'; 128 | src: url('../fonts/merriweather/merriweather-bold-webfont.eot'); 129 | src: url('../fonts/merriweather/merriweather-bold-webfont.eot?#iefix') format('embedded-opentype'), 130 | url('../fonts/merriweather/merriweather-bold-webfont.woff') format('woff'), 131 | url('../fonts/merriweather/merriweather-bold-webfont.ttf') format('truetype'), 132 | url('../fonts/merriweather/merriweather-bold-webfont.svg#merriweatherbold') format('svg'); 133 | font-weight: normal; 134 | font-style: normal; 135 | } 136 | @font-face { 137 | font-family: 'merriweather-bold-italic'; 138 | src: url('../fonts/merriweather/merriweather-bolditalic-webfont.eot'); 139 | src: url('../fonts/merriweather/merriweather-bolditalic-webfont.eot?#iefix') format('embedded-opentype'), 140 | url('../fonts/merriweather/merriweather-bolditalic-webfont.woff') format('woff'), 141 | url('../fonts/merriweather/merriweather-bolditalic-webfont.ttf') format('truetype'), 142 | url('../fonts/merriweather/merriweather-bolditalic-webfont.svg#merriweatherbold_italic') format('svg'); 143 | font-weight: normal; 144 | font-style: normal; 145 | } 146 | @font-face { 147 | font-family: 'merriweather-heavy-italic'; 148 | src: url('../fonts/merriweather/merriweather-heavyitalic-webfont.eot'); 149 | src: url('../fonts/merriweather/merriweather-heavyitalic-webfont.eot?#iefix') format('embedded-opentype'), 150 | url('../fonts/merriweather/merriweather-heavyitalic-webfont.woff') format('woff'), 151 | url('../fonts/merriweather/merriweather-heavyitalic-webfont.ttf') format('truetype'), 152 | url('../fonts/merriweather/merriweather-heavyitalic-webfont.svg#merriweatherheavy_italic') format('svg'); 153 | font-weight: normal; 154 | font-style: normal; 155 | } 156 | @font-face { 157 | font-family: 'merriweather-italic'; 158 | src: url('../fonts/merriweather/merriweather-italic-webfont.eot'); 159 | src: url('../fonts/merriweather/merriweather-italic-webfont.eot?#iefix') format('embedded-opentype'), 160 | url('../fonts/merriweather/merriweather-italic-webfont.woff') format('woff'), 161 | url('../fonts/merriweather/merriweather-italic-webfont.ttf') format('truetype'), 162 | url('../fonts/merriweather/merriweather-italic-webfont.svg#merriweatheritalic') format('svg'); 163 | font-weight: normal; 164 | font-style: normal; 165 | } 166 | @font-face { 167 | font-family: 'merriweather-light'; 168 | src: url('../fonts/merriweather/merriweather-light-webfont.eot'); 169 | src: url('../fonts/merriweather/merriweather-light-webfont.eot?#iefix') format('embedded-opentype'), 170 | url('../fonts/merriweather/merriweather-light-webfont.woff') format('woff'), 171 | url('../fonts/merriweather/merriweather-light-webfont.ttf') format('truetype'), 172 | url('../fonts/merriweather/merriweather-light-webfont.svg#merriweatherlight') format('svg'); 173 | font-weight: normal; 174 | font-style: normal; 175 | } 176 | @font-face { 177 | font-family: 'merriweather-light-italic'; 178 | src: url('../fonts/merriweather/merriweather-lightitalic-webfont.eot'); 179 | src: url('../fonts/merriweather/merriweather-lightitalic-webfont.eot?#iefix') format('embedded-opentype'), 180 | url('../fonts/merriweather/merriweather-lightitalic-webfont.woff') format('woff'), 181 | url('../fonts/merriweather/merriweather-lightitalic-webfont.ttf') format('truetype'), 182 | url('../fonts/merriweather/merriweather-lightitalic-webfont.svg#merriweatherlight_italic') format('svg'); 183 | font-weight: normal; 184 | font-style: normal; 185 | } 186 | @font-face { 187 | font-family: 'merriweather-regular'; 188 | src: url('../fonts/merriweather/merriweather-regular-webfont.eot'); 189 | src: url('../fonts/merriweather/merriweather-regular-webfont.eot?#iefix') format('embedded-opentype'), 190 | url('../fonts/merriweather/merriweather-regular-webfont.woff') format('woff'), 191 | url('../fonts/merriweather/merriweather-regular-webfont.ttf') format('truetype'), 192 | url('../fonts/merriweather/merriweather-regular-webfont.svg#merriweatherregular') format('svg'); 193 | font-weight: normal; 194 | font-style: normal; 195 | } 196 | 197 | -------------------------------------------------------------------------------- /docs/website/css/ionicons/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/ionicons/fonts/ionicons.eot -------------------------------------------------------------------------------- /docs/website/css/ionicons/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/ionicons/fonts/ionicons.ttf -------------------------------------------------------------------------------- /docs/website/css/ionicons/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/ionicons/fonts/ionicons.woff -------------------------------------------------------------------------------- /docs/website/css/micons/fonts/icomoon.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/micons/fonts/icomoon.eot -------------------------------------------------------------------------------- /docs/website/css/micons/fonts/icomoon.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/micons/fonts/icomoon.ttf -------------------------------------------------------------------------------- /docs/website/css/micons/fonts/icomoon.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/css/micons/fonts/icomoon.woff -------------------------------------------------------------------------------- /docs/website/css/micons/micons.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'icomoon'; 3 | src: url('fonts/icomoon.eot?jo2z5t'); 4 | src: url('fonts/icomoon.eot?jo2z5t#iefix') format('embedded-opentype'), 5 | url('fonts/icomoon.ttf?jo2z5t') format('truetype'), 6 | url('fonts/icomoon.woff?jo2z5t') format('woff'), 7 | url('fonts/icomoon.svg?jo2z5t#icomoon') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | [class^="icon-"], [class*=" icon-"] { 13 | /* use !important to prevent issues with browser extensions that change fonts */ 14 | font-family: 'icomoon' !important; 15 | speak: none; 16 | font-style: normal; 17 | font-weight: normal; 18 | font-variant: normal; 19 | text-transform: none; 20 | line-height: 1; 21 | 22 | /* Better Font Rendering =========== */ 23 | -webkit-font-smoothing: antialiased; 24 | -moz-osx-font-smoothing: grayscale; 25 | } 26 | 27 | .icon-align-center:before { 28 | content: "\e900"; 29 | } 30 | .icon-align-justify:before { 31 | content: "\e901"; 32 | } 33 | .icon-align-left:before { 34 | content: "\e902"; 35 | } 36 | .icon-align-right:before { 37 | content: "\e903"; 38 | } 39 | .icon-alt:before { 40 | content: "\e904"; 41 | } 42 | .icon-arrow-right:before { 43 | content: "\e905"; 44 | } 45 | .icon-arrow-up:before { 46 | content: "\e906"; 47 | } 48 | .icon-artboard:before { 49 | content: "\e907"; 50 | } 51 | .icon-at:before { 52 | content: "\e908"; 53 | } 54 | .icon-attachment:before { 55 | content: "\e909"; 56 | } 57 | .icon-backward:before { 58 | content: "\e90a"; 59 | } 60 | .icon-badge:before { 61 | content: "\e90b"; 62 | } 63 | .icon-bank-note:before { 64 | content: "\e90c"; 65 | } 66 | .icon-bar-chart:before { 67 | content: "\e90d"; 68 | } 69 | .icon-basket-ball:before { 70 | content: "\e90e"; 71 | } 72 | .icon-battery-high:before { 73 | content: "\e90f"; 74 | } 75 | .icon-battery-low:before { 76 | content: "\e910"; 77 | } 78 | .icon-bed:before { 79 | content: "\e911"; 80 | } 81 | .icon-bell:before { 82 | content: "\e912"; 83 | } 84 | .icon-bin:before { 85 | content: "\e913"; 86 | } 87 | .icon-block:before { 88 | content: "\e914"; 89 | } 90 | .icon-bluetooth:before { 91 | content: "\e915"; 92 | } 93 | .icon-book:before { 94 | content: "\e916"; 95 | } 96 | .icon-box:before { 97 | content: "\e917"; 98 | } 99 | .icon-brightness:before { 100 | content: "\e918"; 101 | } 102 | .icon-brush:before { 103 | content: "\e919"; 104 | } 105 | .icon-bucket:before { 106 | content: "\e91a"; 107 | } 108 | .icon-building:before { 109 | content: "\e91b"; 110 | } 111 | .icon-calendar:before { 112 | content: "\e91c"; 113 | } 114 | .icon-camera:before { 115 | content: "\e91d"; 116 | } 117 | .icon-car:before { 118 | content: "\e91e"; 119 | } 120 | .icon-card:before { 121 | content: "\e91f"; 122 | } 123 | .icon-chat:before { 124 | content: "\e920"; 125 | } 126 | .icon-circle-bottom-left:before { 127 | content: "\e921"; 128 | } 129 | .icon-circle-bottom-right:before { 130 | content: "\e922"; 131 | } 132 | .icon-circle-down:before { 133 | content: "\e923"; 134 | } 135 | .icon-circle-left:before { 136 | content: "\e924"; 137 | } 138 | .icon-circle-right:before { 139 | content: "\e925"; 140 | } 141 | .icon-circle-top-left:before { 142 | content: "\e926"; 143 | } 144 | .icon-circle-top-right:before { 145 | content: "\e927"; 146 | } 147 | .icon-circle-up:before { 148 | content: "\e928"; 149 | } 150 | .icon-clock:before { 151 | content: "\e929"; 152 | } 153 | .icon-cloud:before { 154 | content: "\e92a"; 155 | } 156 | .icon-cmd:before { 157 | content: "\e92b"; 158 | } 159 | .icon-collapse:before { 160 | content: "\e92c"; 161 | } 162 | .icon-comment:before { 163 | content: "\e92d"; 164 | } 165 | .icon-contrast:before { 166 | content: "\e92e"; 167 | } 168 | .icon-corner-arrow:before { 169 | content: "\e92f"; 170 | } 171 | .icon-cube:before { 172 | content: "\e930"; 173 | } 174 | .icon-cup:before { 175 | content: "\e931"; 176 | } 177 | .icon-cursor:before { 178 | content: "\e932"; 179 | } 180 | .icon-desktop:before { 181 | content: "\e933"; 182 | } 183 | .icon-disk:before { 184 | content: "\e934"; 185 | } 186 | .icon-dollar:before { 187 | content: "\e935"; 188 | } 189 | .icon-download:before { 190 | content: "\e936"; 191 | } 192 | .icon-drawer:before { 193 | content: "\e937"; 194 | } 195 | .icon-drop:before { 196 | content: "\e938"; 197 | } 198 | .icon-earth:before { 199 | content: "\e939"; 200 | } 201 | .icon-edit:before { 202 | content: "\e93a"; 203 | } 204 | .icon-education:before { 205 | content: "\e93b"; 206 | } 207 | .icon-eject:before { 208 | content: "\e93c"; 209 | } 210 | .icon-euro:before { 211 | content: "\e93d"; 212 | } 213 | .icon-expand:before { 214 | content: "\e93e"; 215 | } 216 | .icon-external:before { 217 | content: "\e93f"; 218 | } 219 | .icon-eye:before { 220 | content: "\e940"; 221 | } 222 | .icon-factory:before { 223 | content: "\e941"; 224 | } 225 | .icon-fast-forward:before { 226 | content: "\e942"; 227 | } 228 | .icon-file:before { 229 | content: "\e943"; 230 | } 231 | .icon-file-add:before { 232 | content: "\e944"; 233 | } 234 | .icon-file-remove:before { 235 | content: "\e945"; 236 | } 237 | .icon-files:before { 238 | content: "\e946"; 239 | } 240 | .icon-filter:before { 241 | content: "\e947"; 242 | } 243 | .icon-fire:before { 244 | content: "\e948"; 245 | } 246 | .icon-first-aid:before { 247 | content: "\e949"; 248 | } 249 | .icon-flag:before { 250 | content: "\e94a"; 251 | } 252 | .icon-floppy:before { 253 | content: "\e94b"; 254 | } 255 | .icon-folder:before { 256 | content: "\e94c"; 257 | } 258 | .icon-folder-add:before { 259 | content: "\e94d"; 260 | } 261 | .icon-folder-remove:before { 262 | content: "\e94e"; 263 | } 264 | .icon-fork-knife:before { 265 | content: "\e94f"; 266 | } 267 | .icon-form:before { 268 | content: "\e950"; 269 | } 270 | .icon-frame:before { 271 | content: "\e951"; 272 | } 273 | .icon-full-screen:before { 274 | content: "\e952"; 275 | } 276 | .icon-gift:before { 277 | content: "\e953"; 278 | } 279 | .icon-glass:before { 280 | content: "\e954"; 281 | } 282 | .icon-glasses:before { 283 | content: "\e955"; 284 | } 285 | .icon-grid:before { 286 | content: "\e956"; 287 | } 288 | .icon-group:before { 289 | content: "\e957"; 290 | } 291 | .icon-headset:before { 292 | content: "\e958"; 293 | } 294 | .icon-heart:before { 295 | content: "\e959"; 296 | } 297 | .icon-hide-sdebar-vert:before { 298 | content: "\e95a"; 299 | } 300 | .icon-hide-sidebar-horiz:before { 301 | content: "\e95b"; 302 | } 303 | .icon-home:before { 304 | content: "\e95c"; 305 | } 306 | .icon-id:before { 307 | content: "\e95d"; 308 | } 309 | .icon-image:before { 310 | content: "\e95e"; 311 | } 312 | .icon-info:before { 313 | content: "\e95f"; 314 | } 315 | .icon-invoice:before { 316 | content: "\e960"; 317 | } 318 | .icon-juice:before { 319 | content: "\e961"; 320 | } 321 | .icon-key:before { 322 | content: "\e962"; 323 | } 324 | .icon-lamp:before { 325 | content: "\e963"; 326 | } 327 | .icon-layers:before { 328 | content: "\e964"; 329 | } 330 | .icon-leaf:before { 331 | content: "\e965"; 332 | } 333 | .icon-left:before { 334 | content: "\e966"; 335 | } 336 | .icon-left-right:before { 337 | content: "\e967"; 338 | } 339 | .icon-lego-block:before { 340 | content: "\e968"; 341 | } 342 | .icon-life-buoy:before { 343 | content: "\e969"; 344 | } 345 | .icon-light-bulb:before { 346 | content: "\e96a"; 347 | } 348 | .icon-link:before { 349 | content: "\e96b"; 350 | } 351 | .icon-list:before { 352 | content: "\e96c"; 353 | } 354 | .icon-loading:before { 355 | content: "\e96d"; 356 | } 357 | .icon-logout:before { 358 | content: "\e96e"; 359 | } 360 | .icon-mail:before { 361 | content: "\e96f"; 362 | } 363 | .icon-mail-open:before { 364 | content: "\e970"; 365 | } 366 | .icon-map:before { 367 | content: "\e971"; 368 | } 369 | .icon-margin:before { 370 | content: "\e972"; 371 | } 372 | .icon-megaphone:before { 373 | content: "\e973"; 374 | } 375 | .icon-meh:before { 376 | content: "\e974"; 377 | } 378 | .icon-menu-circle:before { 379 | content: "\e975"; 380 | } 381 | .icon-menu-circle-dots:before { 382 | content: "\e976"; 383 | } 384 | .icon-menu-dots:before { 385 | content: "\e977"; 386 | } 387 | .icon-menu-lines:before { 388 | content: "\e978"; 389 | } 390 | .icon-microphone:before { 391 | content: "\e979"; 392 | } 393 | .icon-minus:before { 394 | content: "\e97a"; 395 | } 396 | .icon-mobile:before { 397 | content: "\e97b"; 398 | } 399 | .icon-mouse:before { 400 | content: "\e97c"; 401 | } 402 | .icon-move:before { 403 | content: "\e97d"; 404 | } 405 | .icon-move-diagonal:before { 406 | content: "\e97e"; 407 | } 408 | .icon-move-horizontal:before { 409 | content: "\e97f"; 410 | } 411 | .icon-move-vertical:before { 412 | content: "\e980"; 413 | } 414 | .icon-mug:before { 415 | content: "\e981"; 416 | } 417 | .icon-music:before { 418 | content: "\e982"; 419 | } 420 | .icon-network:before { 421 | content: "\e983"; 422 | } 423 | .icon-new-file:before { 424 | content: "\e984"; 425 | } 426 | .icon-newspaper:before { 427 | content: "\e985"; 428 | } 429 | .icon-next:before { 430 | content: "\e986"; 431 | } 432 | .icon-no:before { 433 | content: "\e987"; 434 | } 435 | .icon-notes:before { 436 | content: "\e988"; 437 | } 438 | .icon-objects:before { 439 | content: "\e989"; 440 | } 441 | .icon-padding:before { 442 | content: "\e98a"; 443 | } 444 | .icon-padlock:before { 445 | content: "\e98b"; 446 | } 447 | .icon-padlock-open:before { 448 | content: "\e98c"; 449 | } 450 | .icon-paint-brush:before { 451 | content: "\e98d"; 452 | } 453 | .icon-paper-plane:before { 454 | content: "\e98e"; 455 | } 456 | .icon-pause:before { 457 | content: "\e98f"; 458 | } 459 | .icon-pen:before { 460 | content: "\e990"; 461 | } 462 | .icon-pencil:before { 463 | content: "\e991"; 464 | } 465 | .icon-pencil-ruler:before { 466 | content: "\e992"; 467 | } 468 | .icon-phone:before { 469 | content: "\e993"; 470 | } 471 | .icon-pie-chart:before { 472 | content: "\e994"; 473 | } 474 | .icon-pin:before { 475 | content: "\e995"; 476 | } 477 | .icon-pin-2:before { 478 | content: "\e996"; 479 | } 480 | .icon-pin-point:before { 481 | content: "\e997"; 482 | } 483 | .icon-play:before { 484 | content: "\e998"; 485 | } 486 | .icon-plug:before { 487 | content: "\e999"; 488 | } 489 | .icon-plus:before { 490 | content: "\e99a"; 491 | } 492 | .icon-pound:before { 493 | content: "\e99b"; 494 | } 495 | .icon-power-on:before { 496 | content: "\e99c"; 497 | } 498 | .icon-previous:before { 499 | content: "\e99d"; 500 | } 501 | .icon-printer:before { 502 | content: "\e99e"; 503 | } 504 | .icon-projector:before { 505 | content: "\e99f"; 506 | } 507 | .icon-question:before { 508 | content: "\e9a0"; 509 | } 510 | .icon-quote:before { 511 | content: "\e9a1"; 512 | } 513 | .icon-record:before { 514 | content: "\e9a2"; 515 | } 516 | .icon-recycle:before { 517 | content: "\e9a3"; 518 | } 519 | .icon-redo:before { 520 | content: "\e9a4"; 521 | } 522 | .icon-refresh:before { 523 | content: "\e9a5"; 524 | } 525 | .icon-rotate-clock:before { 526 | content: "\e9a6"; 527 | } 528 | .icon-rotate-counter:before { 529 | content: "\e9a7"; 530 | } 531 | .icon-sad:before { 532 | content: "\e9a8"; 533 | } 534 | .icon-scales:before { 535 | content: "\e9a9"; 536 | } 537 | .icon-search:before { 538 | content: "\e9aa"; 539 | } 540 | .icon-selection:before { 541 | content: "\e9ab"; 542 | } 543 | .icon-settings:before { 544 | content: "\e9ac"; 545 | } 546 | .icon-shapes:before { 547 | content: "\e9ad"; 548 | } 549 | .icon-share:before { 550 | content: "\e9ae"; 551 | } 552 | .icon-shield:before { 553 | content: "\e9af"; 554 | } 555 | .icon-shopping-cart:before { 556 | content: "\e9b0"; 557 | } 558 | .icon-show-sidebar-horiz:before { 559 | content: "\e9b1"; 560 | } 561 | .icon-show-sidebar-vert:before { 562 | content: "\e9b2"; 563 | } 564 | .icon-shuffle:before { 565 | content: "\e9b3"; 566 | } 567 | .icon-sign:before { 568 | content: "\e9b4"; 569 | } 570 | .icon-signal:before { 571 | content: "\e9b5"; 572 | } 573 | .icon-skull:before { 574 | content: "\e9b6"; 575 | } 576 | .icon-sliders:before { 577 | content: "\e9b7"; 578 | } 579 | .icon-small-screen:before { 580 | content: "\e9b8"; 581 | } 582 | .icon-smile:before { 583 | content: "\e9b9"; 584 | } 585 | .icon-soap:before { 586 | content: "\e9ba"; 587 | } 588 | .icon-speed-o-meter:before { 589 | content: "\e9bb"; 590 | } 591 | .icon-star:before { 592 | content: "\e9bc"; 593 | } 594 | .icon-stop:before { 595 | content: "\e9bd"; 596 | } 597 | .icon-styling-tools:before { 598 | content: "\e9be"; 599 | } 600 | .icon-suitcase:before { 601 | content: "\e9bf"; 602 | } 603 | .icon-syringe:before { 604 | content: "\e9c0"; 605 | } 606 | .icon-table:before { 607 | content: "\e9c1"; 608 | } 609 | .icon-tag:before { 610 | content: "\e9c2"; 611 | } 612 | .icon-target:before { 613 | content: "\e9c3"; 614 | } 615 | .icon-terminal:before { 616 | content: "\e9c4"; 617 | } 618 | .icon-text:before { 619 | content: "\e9c5"; 620 | } 621 | .icon-thumbs-down:before { 622 | content: "\e9c6"; 623 | } 624 | .icon-thumbs-up:before { 625 | content: "\e9c7"; 626 | } 627 | .icon-thunderbolt:before { 628 | content: "\e9c8"; 629 | } 630 | .icon-tie:before { 631 | content: "\e9c9"; 632 | } 633 | .icon-toggles:before { 634 | content: "\e9ca"; 635 | } 636 | .icon-trophy:before { 637 | content: "\e9cb"; 638 | } 639 | .icon-truck:before { 640 | content: "\e9cc"; 641 | } 642 | .icon-tube:before { 643 | content: "\e9cd"; 644 | } 645 | .icon-tv:before { 646 | content: "\e9ce"; 647 | } 648 | .icon-umbrella:before { 649 | content: "\e9cf"; 650 | } 651 | .icon-undo:before { 652 | content: "\e9d0"; 653 | } 654 | .icon-up:before { 655 | content: "\e9d1"; 656 | } 657 | .icon-update:before { 658 | content: "\e9d2"; 659 | } 660 | .icon-up-down:before { 661 | content: "\e9d3"; 662 | } 663 | .icon-upload:before { 664 | content: "\e9d4"; 665 | } 666 | .icon-user:before { 667 | content: "\e9d5"; 668 | } 669 | .icon-user-add:before { 670 | content: "\e9d6"; 671 | } 672 | .icon-user-remove:before { 673 | content: "\e9d7"; 674 | } 675 | .icon-users:before { 676 | content: "\e9d8"; 677 | } 678 | .icon-video:before { 679 | content: "\e9d9"; 680 | } 681 | .icon-video-camera:before { 682 | content: "\e9da"; 683 | } 684 | .icon-volume-down:before { 685 | content: "\e9db"; 686 | } 687 | .icon-volume-mute:before { 688 | content: "\e9dc"; 689 | } 690 | .icon-volume-up:before { 691 | content: "\e9dd"; 692 | } 693 | .icon-wallet:before { 694 | content: "\e9de"; 695 | } 696 | .icon-wand:before { 697 | content: "\e9df"; 698 | } 699 | .icon-warning:before { 700 | content: "\e9e0"; 701 | } 702 | .icon-wi-fi:before { 703 | content: "\e9e1"; 704 | } 705 | .icon-window:before { 706 | content: "\e9e2"; 707 | } 708 | .icon-wrench:before { 709 | content: "\e9e3"; 710 | } 711 | .icon-yes:before { 712 | content: "\e9e4"; 713 | } 714 | .icon-zoom-in:before { 715 | content: "\e9e5"; 716 | } 717 | .icon-zoom-out:before { 718 | content: "\e9e6"; 719 | } 720 | 721 | -------------------------------------------------------------------------------- /docs/website/css/vendor.css: -------------------------------------------------------------------------------- 1 | /** 2 | * =================================================================== 3 | * 4 | * MetaDetective | Vendor/Third Party CSS 5 | * url: franckferman.github.io/MetaDetective 6 | * created: 27-10-2023 7 | * 8 | * =================================================================== 9 | */ 10 | 11 | 12 | /** 13 | * jQuery FlexSlider v2.5.0 14 | * http://www.woothemes.com/flexslider/ 15 | * 16 | * Copyright 2012 WooThemes 17 | * Free to use under the GPLv2 and later license. 18 | * http://www.gnu.org/licenses/gpl-2.0.html 19 | * 20 | * Contributing author: Tyler Smith (@mbmufffin) 21 | * 22 | * =================================================================== 23 | */ 24 | 25 | /* reset */ 26 | .flex-container a:hover, 27 | .flex-slider a:hover, 28 | .flex-container a:focus, 29 | .flex-slider a:focus { 30 | outline: none; 31 | } 32 | 33 | .slides, 34 | .slides > li, 35 | .flex-control-nav, 36 | .flex-direction-nav { 37 | margin: 0; 38 | padding: 0; 39 | list-style: none; 40 | } 41 | 42 | .flex-pauseplay span { 43 | text-transform: capitalize; 44 | } 45 | 46 | /* base styles */ 47 | .flexslider { 48 | margin: 0; 49 | padding: 0; 50 | } 51 | 52 | .flexslider .slides > li { 53 | display: none; 54 | -webkit-backface-visibility: hidden; 55 | } 56 | 57 | .flexslider .slides img { 58 | width: 100%; 59 | display: block; 60 | } 61 | 62 | .flexslider .slides:after { 63 | content: "\0020"; 64 | display: block; 65 | clear: both; 66 | visibility: hidden; 67 | line-height: 0; 68 | height: 0; 69 | } 70 | 71 | html[xmlns] .flexslider .slides { 72 | display: block; 73 | } 74 | 75 | * html .flexslider .slides { 76 | height: 1%; 77 | } 78 | 79 | .no-js .flexslider .slides > li:first-child { 80 | display: block; 81 | } 82 | 83 | 84 | /** 85 | * Magnific Popup CSS 86 | * =================================================================== 87 | */ 88 | 89 | .mfp-bg { 90 | top: 0; 91 | left: 0; 92 | width: 100%; 93 | height: 100%; 94 | z-index: 1042; 95 | overflow: hidden; 96 | position: fixed; 97 | background: #0b0b0b; 98 | opacity: 0.8; 99 | filter: alpha(opacity=80); 100 | } 101 | 102 | .mfp-wrap { 103 | top: 0; 104 | left: 0; 105 | width: 100%; 106 | height: 100%; 107 | z-index: 1043; 108 | position: fixed; 109 | outline: none !important; 110 | -webkit-backface-visibility: hidden; 111 | } 112 | 113 | .mfp-container { 114 | text-align: center; 115 | position: absolute; 116 | width: 100%; 117 | height: 100%; 118 | left: 0; 119 | top: 0; 120 | padding: 0 8px; 121 | -webkit-box-sizing: border-box; 122 | -moz-box-sizing: border-box; 123 | box-sizing: border-box; 124 | } 125 | 126 | .mfp-container:before { 127 | content: ''; 128 | display: inline-block; 129 | height: 100%; 130 | vertical-align: middle; 131 | } 132 | 133 | .mfp-align-top .mfp-container:before { 134 | display: none; 135 | } 136 | 137 | .mfp-content { 138 | position: relative; 139 | display: inline-block; 140 | vertical-align: middle; 141 | margin: 0 auto; 142 | text-align: left; 143 | z-index: 1045; 144 | } 145 | 146 | .mfp-inline-holder .mfp-content, 147 | .mfp-ajax-holder .mfp-content { 148 | width: 100%; 149 | cursor: auto; 150 | } 151 | 152 | .mfp-ajax-cur { 153 | cursor: progress; 154 | } 155 | 156 | .mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close { 157 | cursor: -moz-zoom-out; 158 | cursor: -webkit-zoom-out; 159 | cursor: zoom-out; 160 | } 161 | 162 | .mfp-zoom { 163 | cursor: pointer; 164 | cursor: -webkit-zoom-in; 165 | cursor: -moz-zoom-in; 166 | cursor: zoom-in; 167 | } 168 | 169 | .mfp-auto-cursor .mfp-content { 170 | cursor: auto; 171 | } 172 | 173 | .mfp-close, 174 | .mfp-arrow, 175 | .mfp-preloader, 176 | .mfp-counter { 177 | -webkit-user-select: none; 178 | -moz-user-select: none; 179 | user-select: none; 180 | } 181 | 182 | .mfp-loading.mfp-figure { 183 | display: none; 184 | } 185 | 186 | .mfp-hide { 187 | display: none !important; 188 | } 189 | 190 | .mfp-preloader { 191 | color: #CCC; 192 | position: absolute; 193 | top: 50%; 194 | width: auto; 195 | text-align: center; 196 | margin-top: -0.8em; 197 | left: 8px; 198 | right: 8px; 199 | z-index: 1044; 200 | } 201 | 202 | .mfp-preloader a { 203 | color: #CCC; 204 | } 205 | 206 | .mfp-preloader a:hover { 207 | color: #FFF; 208 | } 209 | 210 | .mfp-s-ready .mfp-preloader { 211 | display: none; 212 | } 213 | 214 | .mfp-s-error .mfp-content { 215 | display: none; 216 | } 217 | 218 | button.mfp-close, 219 | button.mfp-arrow { 220 | overflow: visible; 221 | cursor: pointer; 222 | background: transparent; 223 | border: 0; 224 | -webkit-appearance: none; 225 | display: block; 226 | outline: none; 227 | padding: 0; 228 | z-index: 1046; 229 | -webkit-box-shadow: none; 230 | box-shadow: none; 231 | } 232 | 233 | button::-moz-focus-inner { 234 | padding: 0; 235 | border: 0; 236 | } 237 | 238 | .mfp-close { 239 | width: 44px; 240 | height: 44px; 241 | line-height: 44px; 242 | position: absolute; 243 | right: 0; 244 | top: 0; 245 | text-decoration: none; 246 | text-align: center; 247 | opacity: 0.65; 248 | filter: alpha(opacity=65); 249 | padding: 0 0 18px 10px; 250 | color: #FFF; 251 | font-style: normal; 252 | font-size: 28px; 253 | font-family: Arial, Baskerville, monospace; 254 | } 255 | 256 | .mfp-close:hover, 257 | .mfp-close:focus { 258 | opacity: 1; 259 | filter: alpha(opacity=100); 260 | } 261 | 262 | .mfp-close:active { 263 | top: 1px; 264 | } 265 | 266 | .mfp-close-btn-in .mfp-close { 267 | color: #333; 268 | } 269 | 270 | .mfp-image-holder .mfp-close, 271 | .mfp-iframe-holder .mfp-close { 272 | color: #FFF; 273 | right: -6px; 274 | text-align: right; 275 | padding-right: 6px; 276 | width: 100%; 277 | } 278 | 279 | .mfp-counter { 280 | position: absolute; 281 | top: 0; 282 | right: 0; 283 | color: #CCC; 284 | font-size: 12px; 285 | line-height: 18px; 286 | white-space: nowrap; 287 | } 288 | 289 | .mfp-arrow { 290 | position: absolute; 291 | opacity: 0.65; 292 | filter: alpha(opacity=65); 293 | margin: 0; 294 | top: 50%; 295 | margin-top: -55px; 296 | padding: 0; 297 | width: 90px; 298 | height: 110px; 299 | -webkit-tap-highlight-color: transparent; 300 | } 301 | 302 | .mfp-arrow:active { 303 | margin-top: -54px; 304 | } 305 | 306 | .mfp-arrow:hover, 307 | .mfp-arrow:focus { 308 | opacity: 1; 309 | filter: alpha(opacity=100); 310 | } 311 | 312 | .mfp-arrow:before, 313 | .mfp-arrow:after, 314 | .mfp-arrow .mfp-b, 315 | .mfp-arrow .mfp-a { 316 | content: ''; 317 | display: block; 318 | width: 0; 319 | height: 0; 320 | position: absolute; 321 | left: 0; 322 | top: 0; 323 | margin-top: 35px; 324 | margin-left: 35px; 325 | border: medium inset transparent; 326 | } 327 | 328 | .mfp-arrow:after, 329 | .mfp-arrow .mfp-a { 330 | border-top-width: 13px; 331 | border-bottom-width: 13px; 332 | top: 8px; 333 | } 334 | 335 | .mfp-arrow:before, 336 | .mfp-arrow .mfp-b { 337 | border-top-width: 21px; 338 | border-bottom-width: 21px; 339 | opacity: 0.7; 340 | } 341 | 342 | .mfp-arrow-left { 343 | left: 0; 344 | } 345 | 346 | .mfp-arrow-left:after, 347 | .mfp-arrow-left .mfp-a { 348 | border-right: 17px solid #FFF; 349 | margin-left: 31px; 350 | } 351 | 352 | .mfp-arrow-left:before, 353 | .mfp-arrow-left .mfp-b { 354 | margin-left: 25px; 355 | border-right: 27px solid #3F3F3F; 356 | } 357 | 358 | .mfp-arrow-right { 359 | right: 0; 360 | } 361 | 362 | .mfp-arrow-right:after, 363 | .mfp-arrow-right .mfp-a { 364 | border-left: 17px solid #FFF; 365 | margin-left: 39px; 366 | } 367 | 368 | .mfp-arrow-right:before, 369 | .mfp-arrow-right .mfp-b { 370 | border-left: 27px solid #3F3F3F; 371 | } 372 | 373 | .mfp-iframe-holder { 374 | padding-top: 40px; 375 | padding-bottom: 40px; 376 | } 377 | 378 | .mfp-iframe-holder .mfp-content { 379 | line-height: 0; 380 | width: 100%; 381 | max-width: 900px; 382 | } 383 | 384 | .mfp-iframe-holder .mfp-close { 385 | top: -40px; 386 | } 387 | 388 | .mfp-iframe-scaler { 389 | width: 100%; 390 | height: 0; 391 | overflow: hidden; 392 | padding-top: 56.25%; 393 | } 394 | 395 | .mfp-iframe-scaler iframe { 396 | position: absolute; 397 | display: block; 398 | top: 0; 399 | left: 0; 400 | width: 100%; 401 | height: 100%; 402 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 403 | background: #000; 404 | } 405 | 406 | /* Main image in popup */ 407 | img.mfp-img { 408 | width: auto; 409 | max-width: 100%; 410 | height: auto; 411 | display: block; 412 | line-height: 0; 413 | -webkit-box-sizing: border-box; 414 | -moz-box-sizing: border-box; 415 | box-sizing: border-box; 416 | padding: 40px 0 40px; 417 | margin: 0 auto; 418 | } 419 | 420 | /* The shadow behind the image */ 421 | .mfp-figure { 422 | line-height: 0; 423 | } 424 | 425 | .mfp-figure:after { 426 | content: ''; 427 | position: absolute; 428 | left: 0; 429 | top: 40px; 430 | bottom: 40px; 431 | display: block; 432 | right: 0; 433 | width: auto; 434 | height: auto; 435 | z-index: -1; 436 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); 437 | background: #444; 438 | } 439 | 440 | .mfp-figure small { 441 | color: #BDBDBD; 442 | display: block; 443 | font-size: 12px; 444 | line-height: 14px; 445 | } 446 | 447 | .mfp-figure figure { 448 | margin: 0; 449 | } 450 | 451 | .mfp-bottom-bar { 452 | margin-top: -36px; 453 | position: absolute; 454 | top: 100%; 455 | left: 0; 456 | width: 100%; 457 | cursor: auto; 458 | } 459 | 460 | .mfp-title { 461 | text-align: left; 462 | line-height: 18px; 463 | color: #F3F3F3; 464 | word-wrap: break-word; 465 | padding-right: 36px; 466 | } 467 | 468 | .mfp-image-holder .mfp-content { 469 | max-width: 100%; 470 | } 471 | 472 | .mfp-gallery .mfp-image-holder .mfp-figure { 473 | cursor: pointer; 474 | } 475 | 476 | @media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) { 477 | /** 478 | * Remove all paddings around the image on small screen 479 | */ 480 | .mfp-img-mobile .mfp-image-holder { 481 | padding-left: 0; 482 | padding-right: 0; 483 | } 484 | 485 | .mfp-img-mobile img.mfp-img { 486 | padding: 0; 487 | } 488 | 489 | .mfp-img-mobile .mfp-figure:after { 490 | top: 0; 491 | bottom: 0; 492 | } 493 | 494 | .mfp-img-mobile .mfp-figure small { 495 | display: inline; 496 | margin-left: 5px; 497 | } 498 | 499 | .mfp-img-mobile .mfp-bottom-bar { 500 | background: rgba(0, 0, 0, 0.6); 501 | bottom: 0; 502 | margin: 0; 503 | top: auto; 504 | padding: 3px 5px; 505 | position: fixed; 506 | -webkit-box-sizing: border-box; 507 | -moz-box-sizing: border-box; 508 | box-sizing: border-box; 509 | } 510 | 511 | .mfp-img-mobile .mfp-bottom-bar:empty { 512 | padding: 0; 513 | } 514 | 515 | .mfp-img-mobile .mfp-counter { 516 | right: 5px; 517 | top: 3px; 518 | } 519 | 520 | .mfp-img-mobile .mfp-close { 521 | top: 0; 522 | right: 0; 523 | width: 35px; 524 | height: 35px; 525 | line-height: 35px; 526 | background: rgba(0, 0, 0, 0.6); 527 | position: fixed; 528 | text-align: center; 529 | padding: 0; 530 | } 531 | } 532 | @media all and (max-width: 900px) { 533 | .mfp-arrow { 534 | -webkit-transform: scale(0.75); 535 | transform: scale(0.75); 536 | } 537 | 538 | .mfp-arrow-left { 539 | -webkit-transform-origin: 0; 540 | transform-origin: 0; 541 | } 542 | 543 | .mfp-arrow-right { 544 | -webkit-transform-origin: 100%; 545 | transform-origin: 100%; 546 | } 547 | 548 | .mfp-container { 549 | padding-left: 6px; 550 | padding-right: 6px; 551 | } 552 | } 553 | .mfp-ie7 .mfp-img { 554 | padding: 0; 555 | } 556 | 557 | .mfp-ie7 .mfp-bottom-bar { 558 | width: 600px; 559 | left: 50%; 560 | margin-left: -300px; 561 | margin-top: 5px; 562 | padding-bottom: 5px; 563 | } 564 | 565 | .mfp-ie7 .mfp-container { 566 | padding: 0; 567 | } 568 | 569 | .mfp-ie7 .mfp-content { 570 | padding-top: 44px; 571 | } 572 | 573 | .mfp-ie7 .mfp-close { 574 | top: 0; 575 | right: 0; 576 | padding-top: 0; 577 | } 578 | 579 | /*# sourceMappingURL=vendor.css.map */ 580 | -------------------------------------------------------------------------------- /docs/website/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/favicon.png -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-black-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-black-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-black-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-black-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-black-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-black-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bold-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bold-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bold-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bolditalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bolditalic-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bolditalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bolditalic-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-bolditalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-bolditalic-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-heavyitalic-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-italic-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-italic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-italic-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-italic-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-light-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-light-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-light-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-lightitalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-lightitalic-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-lightitalic-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-lightitalic-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-lightitalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-lightitalic-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-regular-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-regular-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/merriweather/merriweather-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/merriweather/merriweather-regular-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-bold-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-bold-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-bold-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-regular-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-regular-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/montserrat/montserrat-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/montserrat/montserrat-regular-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-bold-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-bold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-bold-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-bold-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extrabold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extrabold-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extrabold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extrabold-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extrabold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extrabold-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extralight-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extralight-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extralight-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extralight-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-extralight-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-extralight-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-heavy-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-heavy-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-heavy-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-heavy-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-heavy-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-heavy-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-light-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-light-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-light-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-light-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-medium-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-medium-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-medium-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-medium-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-medium-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-regular-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-regular-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-regular-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-regular-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-semibold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-semibold-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-semibold-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-semibold-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-semibold-webfont.woff -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-thin-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-thin-webfont.eot -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-thin-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-thin-webfont.ttf -------------------------------------------------------------------------------- /docs/website/fonts/raleway/raleway-thin-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/fonts/raleway/raleway-thin-webfont.woff -------------------------------------------------------------------------------- /docs/website/images/footer-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/images/footer-logo.png -------------------------------------------------------------------------------- /docs/website/images/intro-bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/images/intro-bg.jpg -------------------------------------------------------------------------------- /docs/website/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/images/logo.png -------------------------------------------------------------------------------- /docs/website/images/play-button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/docs/website/images/play-button.png -------------------------------------------------------------------------------- /docs/website/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | 10 | MetaDetective 11 | 12 | 13 | 14 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 |
39 | 40 |
41 | 42 | 45 | 46 | 54 | 55 | Menu 56 | 57 |
58 | 59 |
60 | 61 | 63 |
64 | 65 |
66 | 67 |
68 |
69 | 70 |
71 | 72 | 75 | 76 |
Unleash Metadata Intelligence with MetaDetective
77 |

MetaDetective

78 | 79 | Learn More 80 | 81 |
82 | 83 |
84 |
85 | 86 | 88 | 89 | 98 | 99 |
100 | 101 | 103 |
104 | 105 |
106 |
107 | 108 |
Features
109 |

Discover MetaDetective's Capabilities

110 | 111 |

MetaDetective is an advanced tool built for seamless metadata extraction and analysis, offering a suite of features tailored for cybersecurity experts.

112 | 113 |
114 |
115 | 116 |
117 | 118 |
119 | 120 |
121 | 122 | 123 | 124 |
125 | 126 |

Tailored Metadata Analysis

127 | 128 |

Designed with efficiency and precision in mind, MetaDetective ensures robust metadata extraction. Its unique approach bridges existing gaps in metadata analysis, offering insightful perspectives crucial for OSINT and pentesting. 129 |

130 | 131 |
132 | 133 |
134 | 135 |
136 | 137 | 138 | 139 |
140 |

Streamlined Data Presentation

141 | 142 |

Beyond mere extraction, MetaDetective showcases metadata in a meticulously categorized manner. It provides a comprehensive view, ensuring users grasp the complete spectrum of data for an array of files. 143 |

144 | 145 | 146 |
147 | 148 |
149 | 150 |
151 | 152 | 153 | 154 |
155 |

Direct Web Scraping

156 | 157 |

Unlike tools relying solely on search engines, MetaDetective directly targets websites for data scraping. This method offers a richer and more precise dataset, spotlighting potential data leaks without the need for complex proxy workarounds. 158 |

159 | 160 | 161 |
162 | 163 |
164 | 165 |
166 | 167 | 168 | 169 |
170 |

Data Exportation

171 | 172 |

Export your analysis findings with ease. MetaDetective offers enhanced data presentation in HTML format for a comprehensive view, while also providing a TXT format for those who need it. 173 |

174 | 175 | 176 |
177 | 178 |
179 | 180 |
181 | 182 | 183 | 184 |
185 |

Complementary Utility

186 | 187 |

MetaDetective is designed for synergy with other tools, making it a quintessential addition for pentesters and OSINT researchers. Enhance your data acquisition and broaden your analysis horizons with MetaDetective. 188 |

189 | 190 | 191 |
192 | 193 |
194 | 195 |
196 | 197 | 198 | 199 |
200 |

Coming Soon

201 | 202 |

MetaDetective is always evolving. Stay tuned for more advanced features and functionalities that are currently under development. We're committed to providing top-notch capabilities to our user community. 203 |

204 | 205 |
206 | 207 |
208 | 209 |
210 | 211 |
212 | 213 |
214 | 215 | 216 | 218 |
219 | 220 |
221 |
222 | 223 |
Faq
224 |

Questions and Answers.

225 | 226 |

Dive into our FAQ section to learn more about MetaDetective, its inception, and its significance in the world of OSINT and pentesting.

227 | 228 |
229 |
230 | 231 |
232 | 233 |
234 | 235 |
236 | 237 |

What is metadata?

238 | 239 |

Metadata is hidden information within files that can describe or point to other data. This can include the origin of the file, the creator, creation date, and much more. They are often embedded within various file types, including documents and images.

240 | 241 |
242 | 243 |
244 | 245 |

Why MetaDetective?

246 | 247 |

MetaDetective was born out of the desire to offer in-depth metadata analysis with an intuitive visualization. With key tools shifting away from pure metadata analysis, the need for a robust alternative arose. MetaDetective fills this void by offering a powerful solution for metadata extraction and analysis.

248 | 249 |
250 | 251 |
252 | 253 |

How can metadata be useful for OSINT or pentesting?

254 | 255 |

Metadata can reveal a wealth of information about a potential target. This might include details about the operating system, software used, locations, and even user habits. For OSINT investigators and pentesters, such information can provide potential entry points, expose vulnerabilities, or give insights into an organization's internal operations.

256 | 257 |
258 | 259 |
260 | 261 |

Why opt for direct web scraping?

262 | 263 |

Searching for information solely through search engines like Google presents limitations, including IP restrictions and the need for proxy use. By opting for direct web scraping, MetaDetective bypasses these challenges, delivering richer and more accurate data while shedding light on potential data leaks.

264 | 265 |
266 | 267 |
268 | 269 |

How can I export the analysis results?

270 | 271 |

Once data is collected and analyzed by MetaDetective, you have the capability to export your findings. The primary export format is HTML, providing a structured and aesthetic presentation of metadata. However, for those preferring a rawer approach, a TXT format export is also available.

272 | 273 |
274 | 275 |
276 | 277 |

What's next for MetaDetective?

278 | 279 |

We are continually working on enhancing MetaDetective by adding new features and optimizing the existing ones. Keep an eye on our GitHub page for updates, and feel free to contribute or share your feedback.

280 | 281 |
282 | 283 |
284 | 285 |
286 | 287 |
288 | 289 |
290 | 291 |
292 | 293 |

Interested in Sponsoring?

294 | 295 |

296 | If you're looking to sponsor and gain visibility with a community of cybersecurity enthusiasts and professionals, this is the perfect spot for you! By becoming a sponsor, you have the opportunity to showcase your brand or product to a dedicated and tech-savvy audience. If you're interested in this unique sponsorship opportunity, please get in touch to discuss potential collaboration. 297 |

298 | 299 |
300 | Contact 301 |
302 | 303 |
304 | 305 |
306 | 307 |
308 | 309 | 310 |
311 | 312 | 314 |
315 | 316 |
317 | 318 |
319 | 320 |

Get started now. Try MetaDetective.

321 | 322 |

Download MetaDetective Now. Available on:

323 | 324 | 339 | 340 |
341 | 342 |
343 | 344 |
345 | 346 | 347 | 349 |
350 | 351 | 402 | 403 | 404 | 422 | 423 |
424 | 425 |
426 |
427 |
428 | 429 | 431 | 432 | 433 | 434 | 435 | 451 | 452 | 453 | 454 | 455 | -------------------------------------------------------------------------------- /docs/website/js/jquery-migrate-1.2.1.min.js: -------------------------------------------------------------------------------- 1 | /*! jQuery Migrate v1.2.1 | (c) 2005, 2013 jQuery Foundation, Inc. and other contributors | jquery.org/license */ 2 | jQuery.migrateMute===void 0&&(jQuery.migrateMute=!0),function(e,t,n){function r(n){var r=t.console;i[n]||(i[n]=!0,e.migrateWarnings.push(n),r&&r.warn&&!e.migrateMute&&(r.warn("JQMIGRATE: "+n),e.migrateTrace&&r.trace&&r.trace()))}function a(t,a,i,o){if(Object.defineProperty)try{return Object.defineProperty(t,a,{configurable:!0,enumerable:!0,get:function(){return r(o),i},set:function(e){r(o),i=e}}),n}catch(s){}e._definePropertyBroken=!0,t[a]=i}var i={};e.migrateWarnings=[],!e.migrateMute&&t.console&&t.console.log&&t.console.log("JQMIGRATE: Logging is active"),e.migrateTrace===n&&(e.migrateTrace=!0),e.migrateReset=function(){i={},e.migrateWarnings.length=0},"BackCompat"===document.compatMode&&r("jQuery is not compatible with Quirks Mode");var o=e("",{size:1}).attr("size")&&e.attrFn,s=e.attr,u=e.attrHooks.value&&e.attrHooks.value.get||function(){return null},c=e.attrHooks.value&&e.attrHooks.value.set||function(){return n},l=/^(?:input|button)$/i,d=/^[238]$/,p=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,f=/^(?:checked|selected)$/i;a(e,"attrFn",o||{},"jQuery.attrFn is deprecated"),e.attr=function(t,a,i,u){var c=a.toLowerCase(),g=t&&t.nodeType;return u&&(4>s.length&&r("jQuery.fn.attr( props, pass ) is deprecated"),t&&!d.test(g)&&(o?a in o:e.isFunction(e.fn[a])))?e(t)[a](i):("type"===a&&i!==n&&l.test(t.nodeName)&&t.parentNode&&r("Can't change the 'type' of an input or button in IE 6/7/8"),!e.attrHooks[c]&&p.test(c)&&(e.attrHooks[c]={get:function(t,r){var a,i=e.prop(t,r);return i===!0||"boolean"!=typeof i&&(a=t.getAttributeNode(r))&&a.nodeValue!==!1?r.toLowerCase():n},set:function(t,n,r){var a;return n===!1?e.removeAttr(t,r):(a=e.propFix[r]||r,a in t&&(t[a]=!0),t.setAttribute(r,r.toLowerCase())),r}},f.test(c)&&r("jQuery.fn.attr('"+c+"') may use property instead of attribute")),s.call(e,t,a,i))},e.attrHooks.value={get:function(e,t){var n=(e.nodeName||"").toLowerCase();return"button"===n?u.apply(this,arguments):("input"!==n&&"option"!==n&&r("jQuery.fn.attr('value') no longer gets properties"),t in e?e.value:null)},set:function(e,t){var a=(e.nodeName||"").toLowerCase();return"button"===a?c.apply(this,arguments):("input"!==a&&"option"!==a&&r("jQuery.fn.attr('value', val) no longer sets properties"),e.value=t,n)}};var g,h,v=e.fn.init,m=e.parseJSON,y=/^([^<]*)(<[\w\W]+>)([^>]*)$/;e.fn.init=function(t,n,a){var i;return t&&"string"==typeof t&&!e.isPlainObject(n)&&(i=y.exec(e.trim(t)))&&i[0]&&("<"!==t.charAt(0)&&r("$(html) HTML strings must start with '<' character"),i[3]&&r("$(html) HTML text after last tag is ignored"),"#"===i[0].charAt(0)&&(r("HTML string cannot start with a '#' character"),e.error("JQMIGRATE: Invalid selector string (XSS)")),n&&n.context&&(n=n.context),e.parseHTML)?v.call(this,e.parseHTML(i[2],n,!0),n,a):v.apply(this,arguments)},e.fn.init.prototype=e.fn,e.parseJSON=function(e){return e||null===e?m.apply(this,arguments):(r("jQuery.parseJSON requires a valid JSON string"),null)},e.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||0>e.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e.browser||(g=e.uaMatch(navigator.userAgent),h={},g.browser&&(h[g.browser]=!0,h.version=g.version),h.chrome?h.webkit=!0:h.webkit&&(h.safari=!0),e.browser=h),a(e,"browser",e.browser,"jQuery.browser is deprecated"),e.sub=function(){function t(e,n){return new t.fn.init(e,n)}e.extend(!0,t,this),t.superclass=this,t.fn=t.prototype=this(),t.fn.constructor=t,t.sub=this.sub,t.fn.init=function(r,a){return a&&a instanceof e&&!(a instanceof t)&&(a=t(a)),e.fn.init.call(this,r,a,n)},t.fn.init.prototype=t.fn;var n=t(document);return r("jQuery.sub() is deprecated"),t},e.ajaxSetup({converters:{"text json":e.parseJSON}});var b=e.fn.data;e.fn.data=function(t){var a,i,o=this[0];return!o||"events"!==t||1!==arguments.length||(a=e.data(o,t),i=e._data(o,t),a!==n&&a!==i||i===n)?b.apply(this,arguments):(r("Use of jQuery.fn.data('events') is deprecated"),i)};var j=/\/(java|ecma)script/i,w=e.fn.andSelf||e.fn.addBack;e.fn.andSelf=function(){return r("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()"),w.apply(this,arguments)},e.clean||(e.clean=function(t,a,i,o){a=a||document,a=!a.nodeType&&a[0]||a,a=a.ownerDocument||a,r("jQuery.clean() is deprecated");var s,u,c,l,d=[];if(e.merge(d,e.buildFragment(t,a).childNodes),i)for(c=function(e){return!e.type||j.test(e.type)?o?o.push(e.parentNode?e.parentNode.removeChild(e):e):i.appendChild(e):n},s=0;null!=(u=d[s]);s++)e.nodeName(u,"script")&&c(u)||(i.appendChild(u),u.getElementsByTagName!==n&&(l=e.grep(e.merge([],u.getElementsByTagName("script")),c),d.splice.apply(d,[s+1,0].concat(l)),s+=l.length));return d});var Q=e.event.add,x=e.event.remove,k=e.event.trigger,N=e.fn.toggle,T=e.fn.live,M=e.fn.die,S="ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",C=RegExp("\\b(?:"+S+")\\b"),H=/(?:^|\s)hover(\.\S+|)\b/,A=function(t){return"string"!=typeof t||e.event.special.hover?t:(H.test(t)&&r("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'"),t&&t.replace(H,"mouseenter$1 mouseleave$1"))};e.event.props&&"attrChange"!==e.event.props[0]&&e.event.props.unshift("attrChange","attrName","relatedNode","srcElement"),e.event.dispatch&&a(e.event,"handle",e.event.dispatch,"jQuery.event.handle is undocumented and deprecated"),e.event.add=function(e,t,n,a,i){e!==document&&C.test(t)&&r("AJAX events should be attached to document: "+t),Q.call(this,e,A(t||""),n,a,i)},e.event.remove=function(e,t,n,r,a){x.call(this,e,A(t)||"",n,r,a)},e.fn.error=function(){var e=Array.prototype.slice.call(arguments,0);return r("jQuery.fn.error() is deprecated"),e.splice(0,0,"error"),arguments.length?this.bind.apply(this,e):(this.triggerHandler.apply(this,e),this)},e.fn.toggle=function(t,n){if(!e.isFunction(t)||!e.isFunction(n))return N.apply(this,arguments);r("jQuery.fn.toggle(handler, handler...) is deprecated");var a=arguments,i=t.guid||e.guid++,o=0,s=function(n){var r=(e._data(this,"lastToggle"+t.guid)||0)%o;return e._data(this,"lastToggle"+t.guid,r+1),n.preventDefault(),a[r].apply(this,arguments)||!1};for(s.guid=i;a.length>o;)a[o++].guid=i;return this.click(s)},e.fn.live=function(t,n,a){return r("jQuery.fn.live() is deprecated"),T?T.apply(this,arguments):(e(this.context).on(t,this.selector,n,a),this)},e.fn.die=function(t,n){return r("jQuery.fn.die() is deprecated"),M?M.apply(this,arguments):(e(this.context).off(t,this.selector||"**",n),this)},e.event.trigger=function(e,t,n,a){return n||C.test(e)||r("Global events are undocumented and deprecated"),k.call(this,e,t,n||document,a)},e.each(S.split("|"),function(t,n){e.event.special[n]={setup:function(){var t=this;return t!==document&&(e.event.add(document,n+"."+e.guid,function(){e.event.trigger(n,null,t,!0)}),e._data(this,n,e.guid++)),!1},teardown:function(){return this!==document&&e.event.remove(document,n+"."+e._data(this,n)),!1}}})}(jQuery,window); -------------------------------------------------------------------------------- /docs/website/js/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * =================================================================== 3 | * main js 4 | * 5 | * ------------------------------------------------------------------- 6 | */ 7 | 8 | (function($) { 9 | 10 | "use strict"; 11 | 12 | /*---------------------------------------------------- */ 13 | /* Preloader 14 | ------------------------------------------------------ */ 15 | $(window).load(function() { 16 | 17 | // will first fade out the loading animation 18 | $("#loader").fadeOut("slow", function(){ 19 | 20 | // will fade out the whole DIV that covers the website. 21 | $("#preloader").delay(300).fadeOut("slow"); 22 | 23 | }); 24 | 25 | }) 26 | 27 | 28 | /*----------------------------------------------------*/ 29 | /* Sticky Navigation 30 | ------------------------------------------------------*/ 31 | $(window).on('scroll', function() { 32 | 33 | var y = $(window).scrollTop(), 34 | topBar = $('header'); 35 | 36 | if (y > 1) { 37 | topBar.addClass('sticky'); 38 | } 39 | else { 40 | topBar.removeClass('sticky'); 41 | } 42 | 43 | }); 44 | 45 | 46 | /*-----------------------------------------------------*/ 47 | /* Mobile Menu 48 | ------------------------------------------------------ */ 49 | var toggleButton = $('.menu-toggle'), 50 | nav = $('.main-navigation'); 51 | 52 | toggleButton.on('click', function(event){ 53 | event.preventDefault(); 54 | 55 | toggleButton.toggleClass('is-clicked'); 56 | nav.slideToggle(); 57 | }); 58 | 59 | if (toggleButton.is(':visible')) nav.addClass('mobile'); 60 | 61 | $(window).resize(function() { 62 | if (toggleButton.is(':visible')) nav.addClass('mobile'); 63 | else nav.removeClass('mobile'); 64 | }); 65 | 66 | $('#main-nav-wrap li a').on("click", function() { 67 | 68 | if (nav.hasClass('mobile')) { 69 | toggleButton.toggleClass('is-clicked'); 70 | nav.fadeOut(); 71 | } 72 | }); 73 | 74 | 75 | /*----------------------------------------------------*/ 76 | /* Highlight the current section in the navigation bar 77 | ------------------------------------------------------*/ 78 | var sections = $("section"), 79 | navigation_links = $("#main-nav-wrap li a"); 80 | 81 | sections.waypoint( { 82 | 83 | handler: function(direction) { 84 | 85 | var active_section; 86 | 87 | active_section = $('section#' + this.element.id); 88 | 89 | if (direction === "up") active_section = active_section.prev(); 90 | 91 | var active_link = $('#main-nav-wrap a[href="#' + active_section.attr("id") + '"]'); 92 | 93 | navigation_links.parent().removeClass("current"); 94 | active_link.parent().addClass("current"); 95 | 96 | }, 97 | 98 | offset: '25%' 99 | 100 | }); 101 | 102 | 103 | /*----------------------------------------------------*/ 104 | /* Smooth Scrolling 105 | ------------------------------------------------------*/ 106 | $('.smoothscroll').on('click', function (e) { 107 | 108 | e.preventDefault(); 109 | 110 | var target = this.hash, 111 | $target = $(target); 112 | 113 | $('html, body').stop().animate({ 114 | 'scrollTop': $target.offset().top 115 | }, 800, 'swing', function () { 116 | window.location.hash = target; 117 | }); 118 | 119 | }); 120 | 121 | 122 | /*----------------------------------------------------*/ 123 | /* Placeholder Plugin Settings 124 | ------------------------------------------------------*/ 125 | 126 | $('input, textarea, select').placeholder() 127 | 128 | 129 | /*---------------------------------------------------- */ 130 | /* FitVids 131 | ------------------------------------------------------ */ 132 | $(".fluid-video-wrapper").fitVids(); 133 | 134 | 135 | /*---------------------------------------------------- */ 136 | /* Modal Popup 137 | ------------------------------------------------------ */ 138 | 139 | $('.video-link a').magnificPopup({ 140 | 141 | type:'inline', 142 | fixedContentPos: false, 143 | removalDelay: 200, 144 | showCloseBtn: false, 145 | mainClass: 'mfp-fade' 146 | 147 | }); 148 | 149 | $(document).on('click', '.close-popup', function (e) { 150 | e.preventDefault(); 151 | $.magnificPopup.close(); 152 | }); 153 | 154 | 155 | /*----------------------------------------------------- */ 156 | /* Back to top 157 | ------------------------------------------------------- */ 158 | var pxShow = 300; // height on which the button will show 159 | var fadeInTime = 400; // how slow/fast you want the button to show 160 | var fadeOutTime = 400; // how slow/fast you want the button to hide 161 | var scrollSpeed = 300; // how slow/fast you want the button to scroll to top. can be a value, 'slow', 'normal' or 'fast' 162 | 163 | // Show or hide the sticky footer button 164 | jQuery(window).scroll(function() { 165 | 166 | if (!( $("#header-search").hasClass('is-visible'))) { 167 | 168 | if (jQuery(window).scrollTop() >= pxShow) { 169 | jQuery("#go-top").fadeIn(fadeInTime); 170 | } else { 171 | jQuery("#go-top").fadeOut(fadeOutTime); 172 | } 173 | 174 | } 175 | 176 | }); 177 | 178 | })(jQuery); 179 | -------------------------------------------------------------------------------- /docs/website/js/modernizr.js: -------------------------------------------------------------------------------- 1 | /* Modernizr 2.8.3 (Custom Build) | MIT & BSD 2 | * Build: http://modernizr.com/download/#-shiv-cssclasses-load 3 | */ 4 | ;window.Modernizr=function(a,b,c){function u(a){j.cssText=a}function v(a,b){return u(prefixes.join(a+";")+(b||""))}function w(a,b){return typeof a===b}function x(a,b){return!!~(""+a).indexOf(b)}function y(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:w(f,"function")?f.bind(d||b):f}return!1}var d="2.8.3",e={},f=!0,g=b.documentElement,h="modernizr",i=b.createElement(h),j=i.style,k,l={}.toString,m={},n={},o={},p=[],q=p.slice,r,s={}.hasOwnProperty,t;!w(s,"undefined")&&!w(s.call,"undefined")?t=function(a,b){return s.call(a,b)}:t=function(a,b){return b in a&&w(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=q.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(q.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(q.call(arguments)))};return e});for(var z in m)t(m,z)&&(r=z.toLowerCase(),e[r]=m[z](),p.push((e[r]?"":"no-")+r));return e.addTest=function(a,b){if(typeof a=="object")for(var d in a)t(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},u(""),i=k=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+p.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f").attr(a.extend(b(this),{type:"text"}))}d.removeAttr("name").data({"placeholder-password":f,"placeholder-id":g}).bind("focus.placeholder",c),f.data({"placeholder-textinput":d,"placeholder-id":g}).before(d)}f=f.removeAttr("id").hide().prevAll('input[type="text"]:first').attr("id",g).show()}f.addClass(m.customClass),f[0].value=f.attr("placeholder")}else f.removeClass(m.customClass)}function e(){try{return document.activeElement}catch(a){}}var f,g,h="[object OperaMini]"==Object.prototype.toString.call(window.operamini),i="placeholder"in document.createElement("input")&&!h,j="placeholder"in document.createElement("textarea")&&!h,k=a.valHooks,l=a.propHooks;if(i&&j)g=a.fn.placeholder=function(){return this},g.input=g.textarea=!0;else{var m={};g=a.fn.placeholder=function(b){var e={customClass:"placeholder"};m=a.extend({},e,b);var f=this;return f.filter((i?"textarea":":input")+"[placeholder]").not("."+m.customClass).bind({"focus.placeholder":c,"blur.placeholder":d}).data("placeholder-enabled",!0).trigger("blur.placeholder"),f},g.input=i,g.textarea=j,f={get:function(b){var c=a(b),d=c.data("placeholder-password");return d?d[0].value:c.data("placeholder-enabled")&&c.hasClass(m.customClass)?"":b.value},set:function(b,f){var g=a(b),h=g.data("placeholder-password");return h?h[0].value=f:g.data("placeholder-enabled")?(""===f?(b.value=f,b!=e()&&d.call(b)):g.hasClass(m.customClass)?c.call(b,!0,f)||(b.value=f):b.value=f,g):b.value=f}},i||(k.input=f,l.value=f),j||(k.textarea=f,l.value=f),a(function(){a(document).delegate("form","submit.placeholder",function(){var b=a("."+m.customClass,this).each(c);setTimeout(function(){b.each(d)},10)})}),a(window).bind("beforeunload.placeholder",function(){a("."+m.customClass).each(function(){this.value=""})})}}); 14 | 15 | 16 | /*jshint browser:true */ 17 | /*! 18 | * FitVids 1.1 19 | * 20 | * Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 21 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 22 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 23 | * 24 | */ 25 | !function(a){"use strict";a.fn.fitVids=function(b){var c={customSelector:null,ignore:null};if(!document.getElementById("fit-vids-style")){var d=document.head||document.getElementsByTagName("head")[0],e=".fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}",f=document.createElement("div");f.innerHTML='

x

",d.appendChild(f.childNodes[1])}return b&&a.extend(c,b),this.each(function(){var b=['iframe[src*="player.vimeo.com"]','iframe[src*="youtube.com"]','iframe[src*="youtube-nocookie.com"]','iframe[src*="kickstarter.com"][src*="video.html"]',"object","embed"];c.customSelector&&b.push(c.customSelector);var d=".fitvidsignore";c.ignore&&(d=d+", "+c.ignore);var e=a(this).find(b.join(","));e=e.not("object object"),e=e.not(d),e.each(function(b){var c=a(this);if(!(c.parents(d).length>0||"embed"===this.tagName.toLowerCase()&&c.parent("object").length||c.parent(".fluid-width-video-wrapper").length)){c.css("height")||c.css("width")||!isNaN(c.attr("height"))&&!isNaN(c.attr("width"))||(c.attr("height",9),c.attr("width",16));var e="object"===this.tagName.toLowerCase()||c.attr("height")&&!isNaN(parseInt(c.attr("height"),10))?parseInt(c.attr("height"),10):c.height(),f=isNaN(parseInt(c.attr("width"),10))?c.width():parseInt(c.attr("width"),10),g=e/f;if(!c.attr("id")){var h="fitvid"+b;c.attr("id",h)}c.wrap('
').parent(".fluid-width-video-wrapper").css("padding-top",100*g+"%"),c.removeAttr("height").removeAttr("width")}})})}}(window.jQuery||window.Zepto); 26 | 27 | 28 | /*! 29 | Waypoints - 4.0.0 30 | Copyright © 2011-2015 Caleb Troughton 31 | Licensed under the MIT license. 32 | https://github.com/imakewebthings/waypoints/blog/master/licenses.txt 33 | */ 34 | !function(){"use strict";function t(o){if(!o)throw new Error("No options passed to Waypoint constructor");if(!o.element)throw new Error("No element option passed to Waypoint constructor");if(!o.handler)throw new Error("No handler option passed to Waypoint constructor");this.key="waypoint-"+e,this.options=t.Adapter.extend({},t.defaults,o),this.element=this.options.element,this.adapter=new t.Adapter(this.element),this.callback=o.handler,this.axis=this.options.horizontal?"horizontal":"vertical",this.enabled=this.options.enabled,this.triggerPoint=null,this.group=t.Group.findOrCreate({name:this.options.group,axis:this.axis}),this.context=t.Context.findOrCreateByElement(this.options.context),t.offsetAliases[this.options.offset]&&(this.options.offset=t.offsetAliases[this.options.offset]),this.group.add(this),this.context.add(this),i[this.key]=this,e+=1}var e=0,i={};t.prototype.queueTrigger=function(t){this.group.queueTrigger(this,t)},t.prototype.trigger=function(t){this.enabled&&this.callback&&this.callback.apply(this,t)},t.prototype.destroy=function(){this.context.remove(this),this.group.remove(this),delete i[this.key]},t.prototype.disable=function(){return this.enabled=!1,this},t.prototype.enable=function(){return this.context.refresh(),this.enabled=!0,this},t.prototype.next=function(){return this.group.next(this)},t.prototype.previous=function(){return this.group.previous(this)},t.invokeAll=function(t){var e=[];for(var o in i)e.push(i[o]);for(var n=0,r=e.length;r>n;n++)e[n][t]()},t.destroyAll=function(){t.invokeAll("destroy")},t.disableAll=function(){t.invokeAll("disable")},t.enableAll=function(){t.invokeAll("enable")},t.refreshAll=function(){t.Context.refreshAll()},t.viewportHeight=function(){return window.innerHeight||document.documentElement.clientHeight},t.viewportWidth=function(){return document.documentElement.clientWidth},t.adapters=[],t.defaults={context:window,continuous:!0,enabled:!0,group:"default",horizontal:!1,offset:0},t.offsetAliases={"bottom-in-view":function(){return this.context.innerHeight()-this.adapter.outerHeight()},"right-in-view":function(){return this.context.innerWidth()-this.adapter.outerWidth()}},window.Waypoint=t}(),function(){"use strict";function t(t){window.setTimeout(t,1e3/60)}function e(t){this.element=t,this.Adapter=n.Adapter,this.adapter=new this.Adapter(t),this.key="waypoint-context-"+i,this.didScroll=!1,this.didResize=!1,this.oldScroll={x:this.adapter.scrollLeft(),y:this.adapter.scrollTop()},this.waypoints={vertical:{},horizontal:{}},t.waypointContextKey=this.key,o[t.waypointContextKey]=this,i+=1,this.createThrottledScrollHandler(),this.createThrottledResizeHandler()}var i=0,o={},n=window.Waypoint,r=window.onload;e.prototype.add=function(t){var e=t.options.horizontal?"horizontal":"vertical";this.waypoints[e][t.key]=t,this.refresh()},e.prototype.checkEmpty=function(){var t=this.Adapter.isEmptyObject(this.waypoints.horizontal),e=this.Adapter.isEmptyObject(this.waypoints.vertical);t&&e&&(this.adapter.off(".waypoints"),delete o[this.key])},e.prototype.createThrottledResizeHandler=function(){function t(){e.handleResize(),e.didResize=!1}var e=this;this.adapter.on("resize.waypoints",function(){e.didResize||(e.didResize=!0,n.requestAnimationFrame(t))})},e.prototype.createThrottledScrollHandler=function(){function t(){e.handleScroll(),e.didScroll=!1}var e=this;this.adapter.on("scroll.waypoints",function(){(!e.didScroll||n.isTouch)&&(e.didScroll=!0,n.requestAnimationFrame(t))})},e.prototype.handleResize=function(){n.Context.refreshAll()},e.prototype.handleScroll=function(){var t={},e={horizontal:{newScroll:this.adapter.scrollLeft(),oldScroll:this.oldScroll.x,forward:"right",backward:"left"},vertical:{newScroll:this.adapter.scrollTop(),oldScroll:this.oldScroll.y,forward:"down",backward:"up"}};for(var i in e){var o=e[i],n=o.newScroll>o.oldScroll,r=n?o.forward:o.backward;for(var s in this.waypoints[i]){var a=this.waypoints[i][s],l=o.oldScroll=a.triggerPoint,p=l&&h,u=!l&&!h;(p||u)&&(a.queueTrigger(r),t[a.group.id]=a.group)}}for(var c in t)t[c].flushTriggers();this.oldScroll={x:e.horizontal.newScroll,y:e.vertical.newScroll}},e.prototype.innerHeight=function(){return this.element==this.element.window?n.viewportHeight():this.adapter.innerHeight()},e.prototype.remove=function(t){delete this.waypoints[t.axis][t.key],this.checkEmpty()},e.prototype.innerWidth=function(){return this.element==this.element.window?n.viewportWidth():this.adapter.innerWidth()},e.prototype.destroy=function(){var t=[];for(var e in this.waypoints)for(var i in this.waypoints[e])t.push(this.waypoints[e][i]);for(var o=0,n=t.length;n>o;o++)t[o].destroy()},e.prototype.refresh=function(){var t,e=this.element==this.element.window,i=e?void 0:this.adapter.offset(),o={};this.handleScroll(),t={horizontal:{contextOffset:e?0:i.left,contextScroll:e?0:this.oldScroll.x,contextDimension:this.innerWidth(),oldScroll:this.oldScroll.x,forward:"right",backward:"left",offsetProp:"left"},vertical:{contextOffset:e?0:i.top,contextScroll:e?0:this.oldScroll.y,contextDimension:this.innerHeight(),oldScroll:this.oldScroll.y,forward:"down",backward:"up",offsetProp:"top"}};for(var r in t){var s=t[r];for(var a in this.waypoints[r]){var l,h,p,u,c,d=this.waypoints[r][a],f=d.options.offset,w=d.triggerPoint,y=0,g=null==w;d.element!==d.element.window&&(y=d.adapter.offset()[s.offsetProp]),"function"==typeof f?f=f.apply(d):"string"==typeof f&&(f=parseFloat(f),d.options.offset.indexOf("%")>-1&&(f=Math.ceil(s.contextDimension*f/100))),l=s.contextScroll-s.contextOffset,d.triggerPoint=y+l-f,h=w=s.oldScroll,u=h&&p,c=!h&&!p,!g&&u?(d.queueTrigger(s.backward),o[d.group.id]=d.group):!g&&c?(d.queueTrigger(s.forward),o[d.group.id]=d.group):g&&s.oldScroll>=d.triggerPoint&&(d.queueTrigger(s.forward),o[d.group.id]=d.group)}}return n.requestAnimationFrame(function(){for(var t in o)o[t].flushTriggers()}),this},e.findOrCreateByElement=function(t){return e.findByElement(t)||new e(t)},e.refreshAll=function(){for(var t in o)o[t].refresh()},e.findByElement=function(t){return o[t.waypointContextKey]},window.onload=function(){r&&r(),e.refreshAll()},n.requestAnimationFrame=function(e){var i=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||t;i.call(window,e)},n.Context=e}(),function(){"use strict";function t(t,e){return t.triggerPoint-e.triggerPoint}function e(t,e){return e.triggerPoint-t.triggerPoint}function i(t){this.name=t.name,this.axis=t.axis,this.id=this.name+"-"+this.axis,this.waypoints=[],this.clearTriggerQueues(),o[this.axis][this.name]=this}var o={vertical:{},horizontal:{}},n=window.Waypoint;i.prototype.add=function(t){this.waypoints.push(t)},i.prototype.clearTriggerQueues=function(){this.triggerQueues={up:[],down:[],left:[],right:[]}},i.prototype.flushTriggers=function(){for(var i in this.triggerQueues){var o=this.triggerQueues[i],n="up"===i||"left"===i;o.sort(n?e:t);for(var r=0,s=o.length;s>r;r+=1){var a=o[r];(a.options.continuous||r===o.length-1)&&a.trigger([i])}}this.clearTriggerQueues()},i.prototype.next=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints),o=i===this.waypoints.length-1;return o?null:this.waypoints[i+1]},i.prototype.previous=function(e){this.waypoints.sort(t);var i=n.Adapter.inArray(e,this.waypoints);return i?this.waypoints[i-1]:null},i.prototype.queueTrigger=function(t,e){this.triggerQueues[e].push(t)},i.prototype.remove=function(t){var e=n.Adapter.inArray(t,this.waypoints);e>-1&&this.waypoints.splice(e,1)},i.prototype.first=function(){return this.waypoints[0]},i.prototype.last=function(){return this.waypoints[this.waypoints.length-1]},i.findOrCreate=function(t){return o[t.axis][t.name]||new i(t)},n.Group=i}(),function(){"use strict";function t(t){this.$element=e(t)}var e=window.jQuery,i=window.Waypoint;e.each(["innerHeight","innerWidth","off","offset","on","outerHeight","outerWidth","scrollLeft","scrollTop"],function(e,i){t.prototype[i]=function(){var t=Array.prototype.slice.call(arguments);return this.$element[i].apply(this.$element,t)}}),e.each(["extend","inArray","isEmptyObject"],function(i,o){t[o]=e[o]}),i.adapters.push({name:"jquery",Adapter:t}),i.Adapter=t}(),function(){"use strict";function t(t){return function(){var i=[],o=arguments[0];return t.isFunction(arguments[0])&&(o=t.extend({},arguments[1]),o.handler=arguments[0]),this.each(function(){var n=t.extend({},o,{element:this});"string"==typeof n.context&&(n.context=t(this).closest(n.context)[0]),i.push(new e(n))}),i}}var e=window.Waypoint;window.jQuery&&(window.jQuery.fn.waypoint=t(window.jQuery)),window.Zepto&&(window.Zepto.fn.waypoint=t(window.Zepto))}(); 35 | 36 | 37 | // Magnific Popup v1.0.1 by Dmitry Semenov 38 | // http://bit.ly/magnific-popup#build=inline+image+ajax+iframe+gallery+retina+imagezoom+fastclick 39 | (function(a){typeof define=="function"&&define.amd?define(["jquery"],a):typeof exports=="object"?a(require("jquery")):a(window.jQuery||window.Zepto)})(function(a){var b="Close",c="BeforeClose",d="AfterClose",e="BeforeAppend",f="MarkupParse",g="Open",h="Change",i="mfp",j="."+i,k="mfp-ready",l="mfp-removing",m="mfp-prevent-close",n,o=function(){},p=!!window.jQuery,q,r=a(window),s,t,u,v,w=function(a,b){n.ev.on(i+a+j,b)},x=function(b,c,d,e){var f=document.createElement("div");return f.className="mfp-"+b,d&&(f.innerHTML=d),e?c&&c.appendChild(f):(f=a(f),c&&f.appendTo(c)),f},y=function(b,c){n.ev.triggerHandler(i+b,c),n.st.callbacks&&(b=b.charAt(0).toLowerCase()+b.slice(1),n.st.callbacks[b]&&n.st.callbacks[b].apply(n,a.isArray(c)?c:[c]))},z=function(b){if(b!==v||!n.currTemplate.closeBtn)n.currTemplate.closeBtn=a(n.st.closeMarkup.replace("%title%",n.st.tClose)),v=b;return n.currTemplate.closeBtn},A=function(){a.magnificPopup.instance||(n=new o,n.init(),a.magnificPopup.instance=n)},B=function(){var a=document.createElement("p").style,b=["ms","O","Moz","Webkit"];if(a.transition!==undefined)return!0;while(b.length)if(b.pop()+"Transition"in a)return!0;return!1};o.prototype={constructor:o,init:function(){var b=navigator.appVersion;n.isIE7=b.indexOf("MSIE 7.")!==-1,n.isIE8=b.indexOf("MSIE 8.")!==-1,n.isLowIE=n.isIE7||n.isIE8,n.isAndroid=/android/gi.test(b),n.isIOS=/iphone|ipad|ipod/gi.test(b),n.supportsTransition=B(),n.probablyMobile=n.isAndroid||n.isIOS||/(Opera Mini)|Kindle|webOS|BlackBerry|(Opera Mobi)|(Windows Phone)|IEMobile/i.test(navigator.userAgent),s=a(document),n.popupsCache={}},open:function(b){var c;if(b.isObj===!1){n.items=b.items.toArray(),n.index=0;var d=b.items,e;for(c=0;c(a||r.height())},_setFocus:function(){(n.st.focus?n.content.find(n.st.focus).eq(0):n.wrap).focus()},_onFocusIn:function(b){if(b.target!==n.wrap[0]&&!a.contains(n.wrap[0],b.target))return n._setFocus(),!1},_parseMarkup:function(b,c,d){var e;d.data&&(c=a.extend(d.data,c)),y(f,[b,c,d]),a.each(c,function(a,c){if(c===undefined||c===!1)return!0;e=a.split("_");if(e.length>1){var d=b.find(j+"-"+e[0]);if(d.length>0){var f=e[1];f==="replaceWith"?d[0]!==c[0]&&d.replaceWith(c):f==="img"?d.is("img")?d.attr("src",c):d.replaceWith(''):d.attr(e[1],c)}}else b.find(j+"-"+a).html(c)})},_getScrollbarSize:function(){if(n.scrollbarSize===undefined){var a=document.createElement("div");a.style.cssText="width: 99px; height: 99px; overflow: scroll; position: absolute; top: -9999px;",document.body.appendChild(a),n.scrollbarSize=a.offsetWidth-a.clientWidth,document.body.removeChild(a)}return n.scrollbarSize}},a.magnificPopup={instance:null,proto:o.prototype,modules:[],open:function(b,c){return A(),b?b=a.extend(!0,{},b):b={},b.isObj=!0,b.index=c||0,this.instance.open(b)},close:function(){return a.magnificPopup.instance&&a.magnificPopup.instance.close()},registerModule:function(b,c){c.options&&(a.magnificPopup.defaults[b]=c.options),a.extend(this.proto,c.proto),this.modules.push(b)},defaults:{disableOn:0,key:null,midClick:!1,mainClass:"",preloader:!0,focus:"",closeOnContentClick:!1,closeOnBgClick:!0,closeBtnInside:!0,showCloseBtn:!0,enableEscapeKey:!0,modal:!1,alignTop:!1,removalDelay:0,prependTo:null,fixedContentPos:"auto",fixedBgPos:"auto",overflowY:"auto",closeMarkup:'',tClose:"Close (Esc)",tLoading:"Loading...",autoFocusLast:!0}},a.fn.magnificPopup=function(b){A();var c=a(this);if(typeof b=="string")if(b==="open"){var d,e=p?c.data("magnificPopup"):c[0].magnificPopup,f=parseInt(arguments[1],10)||0;e.items?d=e.items[f]:(d=c,e.delegate&&(d=d.find(e.delegate)),d=d.eq(f)),n._openClick({mfpEl:d},c,e)}else n.isOpen&&n[b].apply(n,Array.prototype.slice.call(arguments,1));else b=a.extend(!0,{},b),p?c.data("magnificPopup",b):c[0].magnificPopup=b,n.addGroup(c,b);return c};var C="inline",D,E,F,G=function(){F&&(E.after(F.addClass(D)).detach(),F=null)};a.magnificPopup.registerModule(C,{options:{hiddenClass:"hide",markup:"",tNotFound:"Content not found"},proto:{initInline:function(){n.types.push(C),w(b+"."+C,function(){G()})},getInline:function(b,c){G();if(b.src){var d=n.st.inline,e=a(b.src);if(e.length){var f=e[0].parentNode;f&&f.tagName&&(E||(D=d.hiddenClass,E=x(D),D="mfp-"+D),F=e.after(E).detach().removeClass(D)),n.updateStatus("ready")}else n.updateStatus("error",d.tNotFound),e=a("
");return b.inlineElement=e,e}return n.updateStatus("ready"),n._parseMarkup(c,{},b),c}}});var H="ajax",I,J=function(){I&&a(document.body).removeClass(I)},K=function(){J(),n.req&&n.req.abort()};a.magnificPopup.registerModule(H,{options:{settings:null,cursor:"mfp-ajax-cur",tError:'The content could not be loaded.'},proto:{initAjax:function(){n.types.push(H),I=n.st.ajax.cursor,w(b+"."+H,K),w("BeforeChange."+H,K)},getAjax:function(b){I&&a(document.body).addClass(I),n.updateStatus("loading");var c=a.extend({url:b.src,success:function(c,d,e){var f={data:c,xhr:e};y("ParseAjax",f),n.appendContent(a(f.data),H),b.finished=!0,J(),n._setFocus(),setTimeout(function(){n.wrap.addClass(k)},16),n.updateStatus("ready"),y("AjaxContentAdded")},error:function(){J(),b.finished=b.loadError=!0,n.updateStatus("error",n.st.ajax.tError.replace("%url%",b.src))}},n.st.ajax.settings);return n.req=a.ajax(c),""}}});var L,M=function(b){if(b.data&&b.data.title!==undefined)return b.data.title;var c=n.st.image.titleSrc;if(c){if(a.isFunction(c))return c.call(n,b);if(b.el)return b.el.attr(c)||""}return""};a.magnificPopup.registerModule("image",{options:{markup:'
',cursor:"mfp-zoom-out-cur",titleSrc:"title",verticalFit:!0,tError:'The image could not be loaded.'},proto:{initImage:function(){var c=n.st.image,d=".image";n.types.push("image"),w(g+d,function(){n.currItem.type==="image"&&c.cursor&&a(document.body).addClass(c.cursor)}),w(b+d,function(){c.cursor&&a(document.body).removeClass(c.cursor),r.off("resize"+j)}),w("Resize"+d,n.resizeImage),n.isLowIE&&w("AfterChange",n.resizeImage)},resizeImage:function(){var a=n.currItem;if(!a||!a.img)return;if(n.st.image.verticalFit){var b=0;n.isLowIE&&(b=parseInt(a.img.css("padding-top"),10)+parseInt(a.img.css("padding-bottom"),10)),a.img.css("max-height",n.wH-b)}},_onImageHasSize:function(a){a.img&&(a.hasSize=!0,L&&clearInterval(L),a.isCheckingImgSize=!1,y("ImageHasSize",a),a.imgHidden&&(n.content&&n.content.removeClass("mfp-loading"),a.imgHidden=!1))},findImageSize:function(a){var b=0,c=a.img[0],d=function(e){L&&clearInterval(L),L=setInterval(function(){if(c.naturalWidth>0){n._onImageHasSize(a);return}b>200&&clearInterval(L),b++,b===3?d(10):b===40?d(50):b===100&&d(500)},e)};d(1)},getImage:function(b,c){var d=0,e=function(){b&&(b.img[0].complete?(b.img.off(".mfploader"),b===n.currItem&&(n._onImageHasSize(b),n.updateStatus("ready")),b.hasSize=!0,b.loaded=!0,y("ImageLoadComplete")):(d++,d<200?setTimeout(e,100):f()))},f=function(){b&&(b.img.off(".mfploader"),b===n.currItem&&(n._onImageHasSize(b),n.updateStatus("error",g.tError.replace("%url%",b.src))),b.hasSize=!0,b.loaded=!0,b.loadError=!0)},g=n.st.image,h=c.find(".mfp-img");if(h.length){var i=document.createElement("img");i.className="mfp-img",b.el&&b.el.find("img").length&&(i.alt=b.el.find("img").attr("alt")),b.img=a(i).on("load.mfploader",e).on("error.mfploader",f),i.src=b.src,h.is("img")&&(b.img=b.img.clone()),i=b.img[0],i.naturalWidth>0?b.hasSize=!0:i.width||(b.hasSize=!1)}return n._parseMarkup(c,{title:M(b),img_replaceWith:b.img},b),n.resizeImage(),b.hasSize?(L&&clearInterval(L),b.loadError?(c.addClass("mfp-loading"),n.updateStatus("error",g.tError.replace("%url%",b.src))):(c.removeClass("mfp-loading"),n.updateStatus("ready")),c):(n.updateStatus("loading"),b.loading=!0,b.hasSize||(b.imgHidden=!0,c.addClass("mfp-loading"),n.findImageSize(b)),c)}}});var N,O=function(){return N===undefined&&(N=document.createElement("p").style.MozTransform!==undefined),N};a.magnificPopup.registerModule("zoom",{options:{enabled:!1,easing:"ease-in-out",duration:300,opener:function(a){return a.is("img")?a:a.find("img")}},proto:{initZoom:function(){var a=n.st.zoom,d=".zoom",e;if(!a.enabled||!n.supportsTransition)return;var f=a.duration,g=function(b){var c=b.clone().removeAttr("style").removeAttr("class").addClass("mfp-animated-image"),d="all "+a.duration/1e3+"s "+a.easing,e={position:"fixed",zIndex:9999,left:0,top:0,"-webkit-backface-visibility":"hidden"},f="transition";return e["-webkit-"+f]=e["-moz-"+f]=e["-o-"+f]=e[f]=d,c.css(e),c},h=function(){n.content.css("visibility","visible")},i,j;w("BuildControls"+d,function(){if(n._allowZoom()){clearTimeout(i),n.content.css("visibility","hidden"),e=n._getItemToZoom();if(!e){h();return}j=g(e),j.css(n._getOffset()),n.wrap.append(j),i=setTimeout(function(){j.css(n._getOffset(!0)),i=setTimeout(function(){h(),setTimeout(function(){j.remove(),e=j=null,y("ZoomAnimationEnded")},16)},f)},16)}}),w(c+d,function(){if(n._allowZoom()){clearTimeout(i),n.st.removalDelay=f;if(!e){e=n._getItemToZoom();if(!e)return;j=g(e)}j.css(n._getOffset(!0)),n.wrap.append(j),n.content.css("visibility","hidden"),setTimeout(function(){j.css(n._getOffset())},16)}}),w(b+d,function(){n._allowZoom()&&(h(),j&&j.remove(),e=null)})},_allowZoom:function(){return n.currItem.type==="image"},_getItemToZoom:function(){return n.currItem.hasSize?n.currItem.img:!1},_getOffset:function(b){var c;b?c=n.currItem.img:c=n.st.zoom.opener(n.currItem.el||n.currItem);var d=c.offset(),e=parseInt(c.css("padding-top"),10),f=parseInt(c.css("padding-bottom"),10);d.top-=a(window).scrollTop()-e;var g={width:c.width(),height:(p?c.innerHeight():c[0].offsetHeight)-f-e};return O()?g["-moz-transform"]=g.transform="translate("+d.left+"px,"+d.top+"px)":(g.left=d.left,g.top=d.top),g}}});var P="iframe",Q="//about:blank",R=function(a){if(n.currTemplate[P]){var b=n.currTemplate[P].find("iframe");b.length&&(a||(b[0].src=Q),n.isIE8&&b.css("display",a?"block":"none"))}};a.magnificPopup.registerModule(P,{options:{markup:'
',srcAction:"iframe_src",patterns:{youtube:{index:"youtube.com",id:"v=",src:"//www.youtube.com/embed/%id%?autoplay=1"},vimeo:{index:"vimeo.com/",id:"/",src:"//player.vimeo.com/video/%id%?autoplay=1"},gmaps:{index:"//maps.google.",src:"%id%&output=embed"}}},proto:{initIframe:function(){n.types.push(P),w("BeforeChange",function(a,b,c){b!==c&&(b===P?R():c===P&&R(!0))}),w(b+"."+P,function(){R()})},getIframe:function(b,c){var d=b.src,e=n.st.iframe;a.each(e.patterns,function(){if(d.indexOf(this.index)>-1)return this.id&&(typeof this.id=="string"?d=d.substr(d.lastIndexOf(this.id)+this.id.length,d.length):d=this.id.call(this,d)),d=this.src.replace("%id%",d),!1});var f={};return e.srcAction&&(f[e.srcAction]=d),n._parseMarkup(c,f,b),n.updateStatus("ready"),c}}});var S=function(a){var b=n.items.length;return a>b-1?a-b:a<0?b+a:a},T=function(a,b,c){return a.replace(/%curr%/gi,b+1).replace(/%total%/gi,c)};a.magnificPopup.registerModule("gallery",{options:{enabled:!1,arrowMarkup:'',preload:[0,2],navigateByImgClick:!0,arrows:!0,tPrev:"Previous (Left arrow key)",tNext:"Next (Right arrow key)",tCounter:"%curr% of %total%"},proto:{initGallery:function(){var c=n.st.gallery,d=".mfp-gallery",e=Boolean(a.fn.mfpFastClick);n.direction=!0;if(!c||!c.enabled)return!1;u+=" mfp-gallery",w(g+d,function(){c.navigateByImgClick&&n.wrap.on("click"+d,".mfp-img",function(){if(n.items.length>1)return n.next(),!1}),s.on("keydown"+d,function(a){a.keyCode===37?n.prev():a.keyCode===39&&n.next()})}),w("UpdateStatus"+d,function(a,b){b.text&&(b.text=T(b.text,n.currItem.index,n.items.length))}),w(f+d,function(a,b,d,e){var f=n.items.length;d.counter=f>1?T(c.tCounter,e.index,f):""}),w("BuildControls"+d,function(){if(n.items.length>1&&c.arrows&&!n.arrowLeft){var b=c.arrowMarkup,d=n.arrowLeft=a(b.replace(/%title%/gi,c.tPrev).replace(/%dir%/gi,"left")).addClass(m),f=n.arrowRight=a(b.replace(/%title%/gi,c.tNext).replace(/%dir%/gi,"right")).addClass(m),g=e?"mfpFastClick":"click";d[g](function(){n.prev()}),f[g](function(){n.next()}),n.isIE7&&(x("b",d[0],!1,!0),x("a",d[0],!1,!0),x("b",f[0],!1,!0),x("a",f[0],!1,!0)),n.container.append(d.add(f))}}),w(h+d,function(){n._preloadTimeout&&clearTimeout(n._preloadTimeout),n._preloadTimeout=setTimeout(function(){n.preloadNearbyImages(),n._preloadTimeout=null},16)}),w(b+d,function(){s.off(d),n.wrap.off("click"+d),n.arrowLeft&&e&&n.arrowLeft.add(n.arrowRight).destroyMfpFastClick(),n.arrowRight=n.arrowLeft=null})},next:function(){n.direction=!0,n.index=S(n.index+1),n.updateItemHTML()},prev:function(){n.direction=!1,n.index=S(n.index-1),n.updateItemHTML()},goTo:function(a){n.direction=a>=n.index,n.index=a,n.updateItemHTML()},preloadNearbyImages:function(){var a=n.st.gallery.preload,b=Math.min(a[0],n.items.length),c=Math.min(a[1],n.items.length),d;for(d=1;d<=(n.direction?c:b);d++)n._preloadItem(n.index+d);for(d=1;d<=(n.direction?b:c);d++)n._preloadItem(n.index-d)},_preloadItem:function(b){b=S(b);if(n.items[b].preloaded)return;var c=n.items[b];c.parsed||(c=n.parseEl(b)),y("LazyLoad",c),c.type==="image"&&(c.img=a('').on("load.mfploader",function(){c.hasSize=!0}).on("error.mfploader",function(){c.hasSize=!0,c.loadError=!0,y("LazyLoadError",c)}).attr("src",c.src)),c.preloaded=!0}}});var U="retina";a.magnificPopup.registerModule(U,{options:{replaceSrc:function(a){return a.src.replace(/\.\w+$/,function(a){return"@2x"+a})},ratio:1},proto:{initRetina:function(){if(window.devicePixelRatio>1){var a=n.st.retina,b=a.ratio;b=isNaN(b)?b():b,b>1&&(w("ImageHasSize."+U,function(a,c){c.img.css({"max-width":c.img[0].naturalWidth/b,width:"100%"})}),w("ElementParse."+U,function(c,d){d.src=a.replaceSrc(d,b)}))}}}}),function(){var b=1e3,c="ontouchstart"in window,d=function(){r.off("touchmove"+f+" touchend"+f)},e="mfpFastClick",f="."+e;a.fn.mfpFastClick=function(e){return a(this).each(function(){var g=a(this),h;if(c){var i,j,k,l,m,n;g.on("touchstart"+f,function(a){l=!1,n=1,m=a.originalEvent?a.originalEvent.touches[0]:a.touches[0],j=m.clientX,k=m.clientY,r.on("touchmove"+f,function(a){m=a.originalEvent?a.originalEvent.touches:a.touches,n=m.length,m=m[0];if(Math.abs(m.clientX-j)>10||Math.abs(m.clientY-k)>10)l=!0,d()}).on("touchend"+f,function(a){d();if(l||n>1)return;h=!0,a.preventDefault(),clearTimeout(i),i=setTimeout(function(){h=!1},b),e()})})}g.on("click"+f,function(){h||e()})})},a.fn.destroyMfpFastClick=function(){a(this).off("touchstart"+f+" click"+f),c&&r.off("touchmove"+f+" touchend"+f)}}(),A()}) 40 | 41 | 42 | -------------------------------------------------------------------------------- /examples/Black_Organization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/Black_Organization.png -------------------------------------------------------------------------------- /examples/MetaDetective-APTX_4869_report.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/MetaDetective-APTX_4869_report.pdf -------------------------------------------------------------------------------- /examples/MetaDetective-Kogoro_s_Choice.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/MetaDetective-Kogoro_s_Choice.pdf -------------------------------------------------------------------------------- /examples/MetaDetective-Scuba_Diving_Murder_Case.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/MetaDetective-Scuba_Diving_Murder_Case.pdf -------------------------------------------------------------------------------- /examples/MetaDetective.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/MetaDetective.docx -------------------------------------------------------------------------------- /examples/MetaDetective.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/franckferman/MetaDetective/fc2583a0a5c46011d923ee477bfdd31ad50c5a79/examples/MetaDetective.png -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "MetaDetective" 7 | version = "1.0.9" 8 | description = "Unleash Metadata Intelligence with MetaDetective. Your Assistant Beyond Metagoofil." 9 | authors = [{ name = "Franck Ferman", email = "contact@franckferman.fr" }] 10 | license = { file = "LICENSE" } 11 | classifiers = [ 12 | "Programming Language :: Python :: 3", 13 | "License :: OSI Approved :: GNU Affero General Public License v3", 14 | "Operating System :: POSIX :: Linux", 15 | "Topic :: Security", 16 | "Topic :: Utilities" 17 | ] 18 | readme = { file = "README.md", content-type = "text/markdown" } 19 | keywords = ["metadata", "osint", "cyber-security"] 20 | requires-python = ">=3.9" 21 | 22 | [project.urls] 23 | Homepage = "https://github.com/franckferman/MetaDetective" 24 | 25 | [project.scripts] 26 | MetaDetective = "MetaDetective.MetaDetective:main" 27 | 28 | -------------------------------------------------------------------------------- /tests/test_MetaDetective.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import http.client 3 | import json 4 | import os 5 | import re 6 | import subprocess 7 | import tempfile 8 | import unittest 9 | from io import StringIO 10 | from unittest.mock import Mock, patch 11 | 12 | from src.MetaDetective.MetaDetective import (BANNER, show_banner, check_exiftool_installed, 13 | dms_to_dd, parse_dms, get_metadata, matches_any_pattern, 14 | valid_directory, filter_files_by_extension, get_files, 15 | get_address_from_coords, format_gps_data, valid_filename, 16 | is_valid_file_link, valid_url) 17 | 18 | 19 | class TestShowBanner(unittest.TestCase): 20 | def test_show_banner(self): 21 | with patch("sys.stdout", new_callable=StringIO) as mock_stdout: 22 | show_banner() 23 | content = mock_stdout.getvalue() 24 | self.assertEqual(content, BANNER + "\n") 25 | 26 | 27 | class TestExifToolCheck(unittest.TestCase): 28 | 29 | @patch('subprocess.run') 30 | def test_exiftool_is_installed(self, mock_run): 31 | """Test that the function doesn't raise an error when exiftool is installed.""" 32 | mock_run.return_value = None 33 | try: 34 | check_exiftool_installed() 35 | except SystemExit as e: 36 | self.fail(f"Unexpected exit: {e}") 37 | 38 | @patch('subprocess.run') 39 | def test_raises_error_when_exiftool_not_installed(self, mock_run): 40 | """Test that the function raises an error when exiftool is not installed.""" 41 | mock_run.side_effect = FileNotFoundError() 42 | with self.assertRaisesRegex(SystemExit, "Error: exiftool is not installed. Please install it to continue."): 43 | check_exiftool_installed() 44 | 45 | @patch('subprocess.run') 46 | def test_raises_error_on_exiftool_execution_error(self, mock_run): 47 | """Test that the function raises an error when exiftool encounters an execution error.""" 48 | mock_run.side_effect = subprocess.CalledProcessError(returncode=1, cmd=['exiftool', '-ver']) 49 | with self.assertRaisesRegex(SystemExit, "Error: exiftool encountered an error."): 50 | check_exiftool_installed() 51 | 52 | 53 | class TestDMStoDD(unittest.TestCase): 54 | 55 | def test_dms_to_dd_north_positive(self): 56 | result = dms_to_dd(40, 26, 46, 'N') 57 | self.assertAlmostEqual(result, 40.4461111) 58 | 59 | def test_dms_to_dd_south_negative(self): 60 | result = dms_to_dd(40, 26, 46, 'S') 61 | self.assertAlmostEqual(result, -40.4461111) 62 | 63 | def test_dms_to_dd_east_positive(self): 64 | result = dms_to_dd(40, 26, 46, 'E') 65 | self.assertAlmostEqual(result, 40.4461111) 66 | 67 | def test_dms_to_dd_west_negative(self): 68 | result = dms_to_dd(40, 26, 46, 'W') 69 | self.assertAlmostEqual(result, -40.4461111) 70 | 71 | def test_invalid_degrees(self): 72 | with self.assertRaises(ValueError): 73 | dms_to_dd(200, 26, 46, 'N') 74 | 75 | def test_invalid_minutes(self): 76 | with self.assertRaises(ValueError): 77 | dms_to_dd(40, 60, 46, 'N') 78 | 79 | def test_invalid_seconds(self): 80 | with self.assertRaises(ValueError): 81 | dms_to_dd(40, 26, 60, 'N') 82 | 83 | def test_invalid_direction(self): 84 | with self.assertRaises(ValueError): 85 | dms_to_dd(40, 26, 46, 'A') 86 | 87 | def test_case_insensitive_direction(self): 88 | result = dms_to_dd(40, 26, 46, 'n') 89 | self.assertAlmostEqual(result, 40.4461111) 90 | 91 | 92 | class TestParseDMS(unittest.TestCase): 93 | 94 | def test_valid_dms_north(self): 95 | result = parse_dms("50 deg 49' 8.59\" N") 96 | self.assertEqual(result, (50, 49, 8.59, 'N')) 97 | 98 | def test_valid_dms_east(self): 99 | result = parse_dms("50 deg 49' 8.59\" E") 100 | self.assertEqual(result, (50, 49, 8.59, 'E')) 101 | 102 | def test_invalid_direction(self): 103 | with self.assertRaises(ValueError): 104 | parse_dms("50 deg 49' 8.59\" A") 105 | 106 | def test_missing_degrees(self): 107 | with self.assertRaises(ValueError): 108 | parse_dms("49' 8.59\" N") 109 | 110 | def test_missing_minutes(self): 111 | with self.assertRaises(ValueError): 112 | parse_dms("50 deg 8.59\" N") 113 | 114 | def test_missing_seconds(self): 115 | with self.assertRaises(ValueError): 116 | parse_dms("50 deg 49' N") 117 | 118 | def test_case_insensitive_direction(self): 119 | result = parse_dms("50 deg 49' 8.59\" n") 120 | self.assertEqual(result, (50, 49, 8.59, 'N')) 121 | 122 | 123 | class TestGetMetadata(unittest.TestCase): 124 | 125 | def setUp(self): 126 | self.mocked_exiftool_output = """ 127 | ExifTool Version Number : 12.56 128 | File Name : test_MetaDetective-Franck_FERMAN.pdf 129 | Author : Franck FERMAN 130 | Last Modified By : AHaibara 131 | Producer : PDFCreator 2.3.2.6 132 | """ 133 | 134 | @patch("subprocess.run") 135 | def test_get_metadata(self, mock_run): 136 | mock_result = Mock() 137 | mock_result.stdout = self.mocked_exiftool_output 138 | mock_run.return_value = mock_result 139 | 140 | metadata = get_metadata("test_MetaDetective-Franck_FERMAN.pdf", ["File Name", "Author", "Last Modified By"]) 141 | 142 | self.assertIn("File Name", metadata) 143 | self.assertEqual(metadata["File Name"], "test_MetaDetective-Franck_FERMAN.pdf") 144 | self.assertIn("Author", metadata) 145 | self.assertEqual(metadata["Author"], "Franck FERMAN") 146 | self.assertIn("Last Modified By", metadata) 147 | self.assertEqual(metadata["Last Modified By"], "AHaibara") 148 | 149 | @patch("subprocess.run") 150 | def test_get_metadata_with_gps(self, mock_run): 151 | mocked_output_with_gps = """ 152 | ExifTool Version Number : 12.56 153 | File Name : test_MetaDetective-Franck_FERMAN-GPS.jpg 154 | Camera Model Name : Pixel 2 155 | GPS Position : 47 deg 28' 0.86" N, 10 deg 12' 13.50" E 156 | Formatted GPS Position : 47.466906, 10.203750 157 | Address : Hörner Höhenweg, Bolsterlang, Hörnergruppe (VGem), Landkreis Oberallgäu, Bayern, 87538, Deutschland 158 | Map Link : https://nominatim.openstreetmap.org/ui/reverse.html?lat=47.466906&lon=10.203750 159 | """ 160 | 161 | mock_result = Mock() 162 | mock_result.stdout = mocked_output_with_gps 163 | mock_run.return_value = mock_result 164 | 165 | metadata = get_metadata("test_MetaDetective-Franck_FERMAN-GPS.jpg", ["File Name", "Camera Model Name", "Formatted GPS Position", "Address", "Map Link"]) 166 | 167 | self.assertIn("File Name", metadata) 168 | self.assertEqual(metadata["File Name"], "test_MetaDetective-Franck_FERMAN-GPS.jpg") 169 | self.assertIn("Camera Model Name", metadata) 170 | self.assertEqual(metadata["Camera Model Name"], "Pixel 2") 171 | self.assertIn("Formatted GPS Position", metadata) 172 | self.assertEqual(metadata["Formatted GPS Position"], "47.466906, 10.203750") 173 | self.assertIn("Address", metadata) 174 | self.assertEqual(metadata["Address"], "Hörner Höhenweg, Bolsterlang, Hörnergruppe (VGem), Landkreis Oberallgäu, Bayern, 87538, Deutschland") 175 | self.assertIn("Map Link", metadata) 176 | self.assertEqual(metadata["Map Link"], "https://nominatim.openstreetmap.org/ui/reverse.html?lat=47.466906&lon=10.203750") 177 | 178 | @patch("subprocess.run") 179 | def test_exiftool_error(self, mock_run): 180 | mock_run.side_effect = subprocess.CalledProcessError(returncode=1, cmd=["exiftool", "file_path"]) 181 | metadata = get_metadata("file_path", ["Field"]) 182 | self.assertEqual(metadata, {}) 183 | 184 | @patch("subprocess.run") 185 | def test_non_existent_fields(self, mock_run): 186 | mock_result = Mock() 187 | mock_result.stdout = self.mocked_exiftool_output 188 | mock_run.return_value = mock_result 189 | 190 | metadata = get_metadata("test_MetaDetective-Franck_FERMAN.pdf", ["File Name", "NonExistentField"]) 191 | 192 | self.assertIn("File Name", metadata) 193 | self.assertNotIn("NonExistentField", metadata) 194 | 195 | 196 | class TestMatchesAnyPattern(unittest.TestCase): 197 | 198 | def test_matches_pattern(self): 199 | value = "Hello, world!" 200 | patterns = ["^Hello, world!$", "Hello", "world"] 201 | self.assertTrue(matches_any_pattern(value, patterns)) 202 | 203 | def test_does_not_match_pattern(self): 204 | value = "Hello, world!" 205 | patterns = ["^Hello$", "^world!$", "foo"] 206 | self.assertFalse(matches_any_pattern(value, patterns)) 207 | 208 | def test_case_insensitive_matching(self): 209 | value = "Hello, WORLD!" 210 | patterns = ["^hello, world!$", "HELLO", "WORLD"] 211 | self.assertTrue(matches_any_pattern(value, patterns)) 212 | 213 | def test_invalid_pattern(self): 214 | value = "Hello, world!" 215 | patterns = ["Hello[", "world"] 216 | with self.assertRaises(re.error): 217 | matches_any_pattern(value, patterns) 218 | 219 | def test_empty_string(self): 220 | value = "" 221 | patterns = ["^Hello, world!$", "Hello", "world"] 222 | self.assertFalse(matches_any_pattern(value, patterns)) 223 | 224 | def test_empty_patterns(self): 225 | value = "Hello, world!" 226 | patterns = [] 227 | self.assertFalse(matches_any_pattern(value, patterns)) 228 | 229 | def test_matches_empty_pattern(self): 230 | value = "Hello, world!" 231 | patterns = ["^Hello, world!$", "", "world"] 232 | self.assertTrue(matches_any_pattern(value, patterns)) 233 | 234 | 235 | class TestValidDirectory(unittest.TestCase): 236 | 237 | def setUp(self): 238 | self.temp_dir = tempfile.mkdtemp() 239 | 240 | self.temp_file = tempfile.NamedTemporaryFile(delete=False) 241 | self.temp_file.close() 242 | 243 | def tearDown(self): 244 | os.remove(self.temp_file.name) 245 | os.rmdir(self.temp_dir) 246 | 247 | def test_valid_directory(self): 248 | path = valid_directory(self.temp_dir) 249 | self.assertEqual(path, self.temp_dir) 250 | 251 | def test_invalid_directory_not_exist(self): 252 | with self.assertRaises(argparse.ArgumentTypeError): 253 | valid_directory("/path/that/doesnt/exist") 254 | 255 | def test_invalid_directory_is_file(self): 256 | with self.assertRaises(argparse.ArgumentTypeError): 257 | valid_directory(self.temp_file.name) 258 | 259 | def test_empty_directory_path(self): 260 | with self.assertRaises(argparse.ArgumentTypeError): 261 | valid_directory("") 262 | 263 | 264 | class TestFilterFilesByExtension(unittest.TestCase): 265 | 266 | def test_filter_files(self): 267 | files = ["test.txt", "example.jpg", "another.png", "sample.doc", "more.docx"] 268 | extensions = [".jpg", ".png"] 269 | filtered = filter_files_by_extension(files, extensions) 270 | self.assertEqual(filtered, ["example.jpg", "another.png"]) 271 | 272 | def test_invalid_files_argument(self): 273 | with self.assertRaises(TypeError): 274 | filter_files_by_extension("string_instead_of_list", [".jpg"]) 275 | 276 | def test_invalid_files_element(self): 277 | with self.assertRaises(TypeError): 278 | filter_files_by_extension([123, "example.jpg"], [".jpg"]) 279 | 280 | def test_invalid_extensions_argument(self): 281 | with self.assertRaises(TypeError): 282 | filter_files_by_extension(["example.jpg"], "string_instead_of_list") 283 | 284 | def test_invalid_extensions_element(self): 285 | with self.assertRaises(TypeError): 286 | filter_files_by_extension(["example.jpg"], [".jpg", 123]) 287 | 288 | def test_empty_files_list(self): 289 | extensions = [".jpg", ".png"] 290 | filtered = filter_files_by_extension([], extensions) 291 | self.assertEqual(filtered, []) 292 | 293 | def test_no_matching_files(self): 294 | files = ["test.txt", "sample.doc", "more.docx"] 295 | extensions = [".jpg", ".png"] 296 | filtered = filter_files_by_extension(files, extensions) 297 | self.assertEqual(filtered, []) 298 | 299 | 300 | class TestGetFiles(unittest.TestCase): 301 | 302 | def setUp(self): 303 | self.mock_args_with_directory = Mock() 304 | self.mock_args_with_directory.directory = "/mock/directory" 305 | self.mock_args_with_directory.type = ["all"] 306 | self.mock_args_with_directory.files = [] 307 | 308 | self.mock_args_with_files = Mock() 309 | self.mock_args_with_files.directory = None 310 | self.mock_args_with_files.type = ["all"] 311 | self.mock_args_with_files.files = ["/path/to/file1.txt", "/path/to/file2.jpg"] 312 | 313 | @patch("os.path.exists", return_value=True) 314 | @patch("os.path.isdir", return_value=True) 315 | @patch("os.listdir", return_value=["file1.txt", "file2.jpg"]) 316 | def test_get_files_from_directory(self, mock_listdir, mock_isdir, mock_exists): 317 | files = get_files(self.mock_args_with_directory) 318 | self.assertEqual(files, ["/mock/directory/file1.txt", "/mock/directory/file2.jpg"]) 319 | 320 | @patch("os.path.exists", return_value=True) 321 | @patch("os.path.isdir", return_value=True) 322 | @patch("os.listdir", return_value=["file1.txt", "file2.jpg"]) 323 | def test_get_files_from_directory_with_filter(self, mock_listdir, mock_isdir, mock_exists): 324 | self.mock_args_with_directory.type = [".txt"] 325 | files = get_files(self.mock_args_with_directory) 326 | self.assertEqual(files, ["/mock/directory/file1.txt"]) 327 | 328 | def test_get_files_from_args(self): 329 | files = get_files(self.mock_args_with_files) 330 | self.assertEqual(files, ["/path/to/file1.txt", "/path/to/file2.jpg"]) 331 | 332 | @patch("os.path.isdir", return_value=False) 333 | def test_invalid_directory(self, mock_isdir): 334 | with self.assertRaises(ValueError): 335 | get_files(self.mock_args_with_directory) 336 | 337 | @patch("os.path.isdir", return_value=True) 338 | @patch("os.listdir", return_value=[]) 339 | def test_no_files_in_directory(self, mock_listdir, mock_isdir): 340 | with self.assertRaises(ValueError): 341 | get_files(self.mock_args_with_directory) 342 | 343 | def test_no_files_in_args(self): 344 | self.mock_args_with_files.files = [] 345 | with self.assertRaises(ValueError): 346 | get_files(self.mock_args_with_files) 347 | 348 | @patch("http.client.HTTPSConnection") 349 | def test_valid_response(self, MockHTTPSConnection): 350 | mock_response = Mock() 351 | mock_response.read.return_value = '{"display_name": "Berlin, Germany"}'.encode("utf-8") 352 | MockHTTPSConnection().getresponse.return_value = mock_response 353 | 354 | address = get_address_from_coords("52.5200", "13.4050") 355 | self.assertEqual(address, "Berlin, Germany") 356 | 357 | @patch("http.client.HTTPSConnection") 358 | def test_invalid_json(self, MockHTTPSConnection): 359 | mock_response = Mock() 360 | mock_response.read.return_value = 'Invalid JSON'.encode("utf-8") 361 | MockHTTPSConnection().getresponse.return_value = mock_response 362 | 363 | with self.assertRaisesRegex(json.JSONDecodeError, 'Expecting value'): 364 | get_address_from_coords("52.5200", "13.4050") 365 | 366 | @patch("http.client.HTTPSConnection") 367 | def test_http_error(self, MockHTTPSConnection): 368 | MockHTTPSConnection().request.side_effect = http.client.HTTPException("HTTP error") 369 | 370 | with self.assertRaises(http.client.HTTPException): 371 | get_address_from_coords("52.5200", "13.4050") 372 | 373 | @patch("http.client.HTTPSConnection") 374 | def test_no_display_name(self, MockHTTPSConnection): 375 | mock_response = Mock() 376 | mock_response.read.return_value = '{"name": "Berlin"}'.encode("utf-8") 377 | MockHTTPSConnection().getresponse.return_value = mock_response 378 | 379 | address = get_address_from_coords("52.5200", "13.4050") 380 | self.assertEqual(address, "") 381 | 382 | 383 | class TestFormatGPSData(unittest.TestCase): 384 | 385 | def test_valid_formatted_gps_data_with_address(self): 386 | metadata = {"Formatted GPS Position": "52.5200, 13.4050"} 387 | 388 | format_gps_data(metadata) 389 | 390 | self.assertIn("Address", metadata) 391 | self.assertIn("Map Link", metadata) 392 | self.assertIn("52.5200", metadata["Map Link"]) 393 | self.assertIn("13.4050", metadata["Map Link"]) 394 | 395 | def test_no_formatted_gps_data(self): 396 | metadata = {"Some Other Data": "12345"} 397 | 398 | format_gps_data(metadata) 399 | 400 | self.assertNotIn("Address", metadata) 401 | self.assertNotIn("Map Link", metadata) 402 | 403 | def test_invalid_formatted_gps_data(self): 404 | metadata = {"Formatted GPS Position": "52.5200; 13.4050"} 405 | 406 | with self.assertRaises(ValueError): 407 | format_gps_data(metadata) 408 | 409 | 410 | class TestValidFilename(unittest.TestCase): 411 | 412 | def test_valid_filename(self): 413 | """Test a valid filename.""" 414 | filename = "example_123" 415 | self.assertEqual(valid_filename(filename), filename) 416 | 417 | def test_empty_filename(self): 418 | """Test an empty filename.""" 419 | with self.assertRaises(argparse.ArgumentTypeError): 420 | valid_filename("") 421 | 422 | def test_long_filename(self): 423 | """Test a filename longer than 16 characters.""" 424 | with self.assertRaises(argparse.ArgumentTypeError): 425 | valid_filename("a" * 17) 426 | 427 | def test_filename_ending_with_dash(self): 428 | """Test a filename ending with '-'.""" 429 | with self.assertRaises(argparse.ArgumentTypeError): 430 | valid_filename("example-") 431 | 432 | def test_filename_ending_with_underscore(self): 433 | """Test a filename ending with '_'.""" 434 | with self.assertRaises(argparse.ArgumentTypeError): 435 | valid_filename("example_") 436 | 437 | def test_filename_with_invalid_characters(self): 438 | """Test a filename with other invalid characters.""" 439 | with self.assertRaises(argparse.ArgumentTypeError): 440 | valid_filename("example@123") 441 | 442 | 443 | class TestIsValidFileLink(unittest.TestCase): 444 | 445 | def test_valid_file_link(self): 446 | """Test a valid file link.""" 447 | link = "http://example.com/file.jpg" 448 | self.assertTrue(is_valid_file_link(link)) 449 | 450 | def test_invalid_extension(self): 451 | """Test a link with no valid file extension.""" 452 | link = "http://example.com/file.txt" 453 | self.assertFalse(is_valid_file_link(link)) 454 | 455 | def test_extension_not_at_end(self): 456 | """Test a link where the extension is not at the end.""" 457 | link = "http://example.com/file.jpg?query=123" 458 | self.assertTrue(is_valid_file_link(link)) 459 | 460 | def test_no_path_in_link(self): 461 | """Test a link without any path.""" 462 | link = "http://example.com" 463 | self.assertFalse(is_valid_file_link(link)) 464 | 465 | def test_empty_link(self): 466 | """Test an empty link.""" 467 | link = "" 468 | self.assertFalse(is_valid_file_link(link)) 469 | 470 | 471 | class TestValidUrl(unittest.TestCase): 472 | 473 | def test_valid_http_url(self): 474 | """Test a valid HTTP URL.""" 475 | url = "http://example.com" 476 | self.assertEqual(valid_url(url), url) 477 | 478 | def test_valid_https_url(self): 479 | """Test a valid HTTPS URL.""" 480 | url = "https://secure.example.com" 481 | self.assertEqual(valid_url(url), url) 482 | 483 | def test_invalid_url_no_protocol(self): 484 | """Test an invalid URL that lacks a protocol.""" 485 | url = "example.com" 486 | with self.assertRaises(argparse.ArgumentTypeError): 487 | valid_url(url) 488 | 489 | def test_empty_url(self): 490 | """Test an empty URL.""" 491 | url = "" 492 | with self.assertRaises(argparse.ArgumentTypeError): 493 | valid_url(url) 494 | 495 | 496 | if __name__ == '__main__': 497 | unittest.main() 498 | --------------------------------------------------------------------------------