├── scripts ├── lib │ ├── __init__.py │ ├── config.py │ ├── github.py │ └── util.py └── cpplint.py ├── include.js ├── .vscode ├── settings.json └── launch.json ├── .gitmodules ├── .travis.yml ├── BUILD.gn ├── test ├── util.cpp ├── util.h ├── test-main.cpp ├── testResult2.h ├── binding.gyp └── test-bloom.cpp ├── brave └── BUILD.gn ├── .gitignore ├── base.h ├── addon.cpp ├── binding.gyp ├── sample └── binding.gyp ├── Makefile ├── hashFn.cpp ├── package.json ├── BloomFilterWrap.h ├── main.cpp ├── hashFn.h ├── README.md ├── BloomFilterWrap.cpp ├── BloomFilter.cpp ├── BloomFilter.h └── LICENSE /scripts/lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /include.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | console.log(path.relative('.', __dirname),'..'); 3 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/depot_tools"] 2 | path = vendor/depot_tools 3 | url = https://chromium.googlesource.com/chromium/tools/depot_tools.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "5.2" 4 | - "node" 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - gcc-4.8 11 | - g++-4.8 12 | - ninja-build 13 | 14 | env: 15 | - TRAVIS=travis CXX=g++-4.8 16 | -------------------------------------------------------------------------------- /BUILD.gn: -------------------------------------------------------------------------------- 1 | config("external_config") { 2 | include_dirs = [ "." ] 3 | } 4 | 5 | source_set("bloom-filter-cpp") { 6 | public_configs = [ ":external_config" ] 7 | 8 | sources = [ 9 | "BloomFilter.cpp", 10 | "BloomFilter.h", 11 | "hashFn.cpp", 12 | "hashFn.h", 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/util.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include "CppUnitLite/TestHarness.h" 8 | #include "./util.h" 9 | -------------------------------------------------------------------------------- /brave/BUILD.gn: -------------------------------------------------------------------------------- 1 | config("internal_config") { 2 | } 3 | 4 | config("external_config") { 5 | include_dirs = [ ".." ] 6 | } 7 | 8 | source_set("bloom-filter-cpp") { 9 | configs += [ ":internal_config" ] 10 | public_configs = [ ":external_config" ] 11 | sources = [ 12 | "../BloomFilter.cpp", 13 | "../BloomFilter.h", 14 | "../hashFn.cpp", 15 | "../hashFn.h", 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | *.obj 6 | 7 | # Precompiled Headers 8 | *.gch 9 | *.pch 10 | 11 | # Compiled Dynamic libraries 12 | *.so 13 | *.dylib 14 | *.dll 15 | 16 | # Fortran module files 17 | *.mod 18 | 19 | # Compiled Static libraries 20 | *.lai 21 | *.la 22 | *.a 23 | *.lib 24 | 25 | # Executables 26 | *.exe 27 | *.out 28 | *.app 29 | 30 | build/ 31 | node_modules/ 32 | run 33 | 34 | *.pyc 35 | -------------------------------------------------------------------------------- /test/util.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef TEST_UTIL_H_ 7 | #define TEST_UTIL_H_ 8 | 9 | #include 10 | 11 | SimpleString StringFrom(const std::string& value); 12 | 13 | #endif // TEST_UTIL_H_ 14 | -------------------------------------------------------------------------------- /base.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef BASE_H_ 7 | #define BASE_H_ 8 | 9 | #if !defined(nullptr) && !defined(_MSC_VER) 10 | #define nullptr 0 11 | #endif 12 | 13 | #include 14 | 15 | #endif // BASE_H_ 16 | -------------------------------------------------------------------------------- /addon.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include "BloomFilterWrap.h" 8 | 9 | namespace BloomFilterWrap { 10 | 11 | using v8::Local; 12 | using v8::Object; 13 | 14 | void InitAll(Local exports) { 15 | BloomFilterWrap::Init(exports); 16 | } 17 | 18 | NODE_MODULE(addon, InitAll) 19 | 20 | } // namespace BloomFilterWrap 21 | -------------------------------------------------------------------------------- /test/test-main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include "./CppUnitLite/TestHarness.h" 8 | #include "./util.h" 9 | #include "./testResult2.h" 10 | 11 | SimpleString StringFrom(const std::string& value) { 12 | return SimpleString(value.c_str()); 13 | } 14 | 15 | int main() { 16 | TestResult2 tr; 17 | TestRegistry::runAllTests(tr); 18 | return tr.hasFailures ? 1 : 0; 19 | } 20 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [{ 3 | "target_name": "bloom-filter-cpp", 4 | "sources": [ 5 | "addon.cpp", 6 | "BloomFilterWrap.cpp", 7 | "BloomFilterWrap.h", 8 | "BloomFilter.cpp", 9 | "BloomFilter.h", 10 | "hashFn.cpp", 11 | ], 12 | "include_dirs": [ 13 | ".", 14 | ], 15 | "conditions": [ 16 | ['OS=="win"', { 17 | }, { 18 | 'cflags_cc': [ '-fexceptions' ] 19 | } 20 | ] 21 | ], 22 | "xcode_settings": { 23 | "OTHER_CFLAGS": [ "-ObjC" ], 24 | "OTHER_CPLUSPLUSFLAGS" : ["-std=c++11","-stdlib=libc++", "-v"], 25 | "MACOSX_DEPLOYMENT_TARGET": "10.9", 26 | "GCC_ENABLE_CPP_EXCEPTIONS": "YES", 27 | }, 28 | }] 29 | } 30 | -------------------------------------------------------------------------------- /test/testResult2.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef TEST_TESTRESULT2_H_ 7 | #define TEST_TESTRESULT2_H_ 8 | 9 | #include "./CppUnitLite/TestHarness.h" 10 | 11 | class TestResult2 : public TestResult { 12 | public: 13 | TestResult2() : hasFailures(false) { 14 | } 15 | virtual void addFailure(const Failure& failure) { 16 | hasFailures = true; 17 | TestResult::addFailure(failure); 18 | } 19 | bool hasFailures; 20 | }; 21 | 22 | #endif // TEST_TESTRESULT2_H_ 23 | -------------------------------------------------------------------------------- /sample/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [{ 3 | "target_name": "sample", 4 | "type": "executable", 5 | "sources": [ 6 | "../main.cpp", 7 | "../BloomFilter.cpp", 8 | "../BloomFilter.h", 9 | "../hashFn.cpp", 10 | ], 11 | "include_dirs": [ 12 | "..", 13 | ], 14 | "conditions": [ 15 | ['OS=="win"', { 16 | }, { 17 | 'cflags_cc': [ '-fexceptions' ] 18 | } 19 | ] 20 | ], 21 | "xcode_settings": { 22 | "OTHER_CFLAGS": [ "-ObjC" ], 23 | "OTHER_CPLUSPLUSFLAGS" : ["-std=c++11","-stdlib=libc++", "-v"], 24 | "OTHER_LDFLAGS": ["-stdlib=libc++"], 25 | "MACOSX_DEPLOYMENT_TARGET": "10.9", 26 | "GCC_ENABLE_CPP_EXCEPTIONS": "YES", 27 | }, 28 | }] 29 | } 30 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: build 2 | .PHONY: test 3 | .PHONY: sample 4 | 5 | build: 6 | ./node_modules/.bin/node-gyp rebuild 7 | 8 | test: 9 | cd test 10 | ./node_modules/node-gyp/gyp/gyp_main.py --generator-output=./build --depth=. -f ninja test/binding.gyp 11 | ./node_modules/node-gyp/gyp/gyp_main.py --generator-output=./build --depth=. -f xcode test/binding.gyp 12 | ninja -C ./build/out/Default -f build.ninja 13 | ./build/out/Default/test || [ $$? -eq 0 ] 14 | 15 | sample: 16 | cd sample 17 | ./node_modules/node-gyp/gyp/gyp_main.py --generator-output=./build --depth=. -f ninja sample/binding.gyp 18 | ./node_modules/node-gyp/gyp/gyp_main.py --generator-output=./build --depth=. -f xcode sample/binding.gyp 19 | ninja -C ./build/out/Default -f build.ninja 20 | ./build/out/Default/sample 21 | 22 | clean: 23 | rm -Rf build 24 | -------------------------------------------------------------------------------- /hashFn.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include "hashFn.h" 7 | 8 | uint64_t HashFn::operator()(const char *input, int len, 9 | unsigned char lastCharCode, uint64_t lastHash) { 10 | // See the abracadabra example: 11 | // https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm 12 | return (lastHash - lastCharCode * 13 | customPow(&precomputedPowers, precompute, p, len - 1)) * 14 | p + input[len - 1]; 15 | } 16 | 17 | uint64_t HashFn::operator()(const char *input, int len) { 18 | uint64_t total = 0; 19 | for (int i = 0; i < len; i++) { 20 | total += input[i] * 21 | customPow(&precomputedPowers, precompute, p, len - i - 1); 22 | } 23 | return total; 24 | } 25 | -------------------------------------------------------------------------------- /test/binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [{ 3 | "target_name": "test", 4 | "type": "executable", 5 | "sources": [ 6 | "../test/test-main.cpp", 7 | "../test/test-bloom.cpp", 8 | "../test/util.cpp", 9 | "../BloomFilter.cpp", 10 | "../hashFn.cpp", 11 | ], 12 | "include_dirs": [ 13 | "..", 14 | '../node_modules/cppunitlite', 15 | '../node_modules/nan', 16 | ], 17 | "dependencies": [ 18 | "../node_modules/cppunitlite/binding.gyp:CppUnitLite", 19 | ], 20 | "conditions": [ 21 | ['OS=="win"', { 22 | }, { 23 | 'cflags_cc': [ '-fexceptions' ] 24 | } 25 | ] 26 | ], 27 | "xcode_settings": { 28 | "OTHER_CFLAGS": [ "-ObjC" ], 29 | "OTHER_CPLUSPLUSFLAGS" : ["-std=c++11","-stdlib=libc++", "-v"], 30 | "OTHER_LDFLAGS": ["-stdlib=libc++"], 31 | "MACOSX_DEPLOYMENT_TARGET": "10.9", 32 | "GCC_ENABLE_CPP_EXCEPTIONS": "YES", 33 | }, 34 | }] 35 | } 36 | 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bloom-filter-cpp", 3 | "main": "./build/Release/bloom-filter-cpp", 4 | "version": "1.2.2", 5 | "description": "", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "cppunitlite": "^1.0.0", 12 | "nan": "^2.13.2", 13 | "node-gyp": "^4.0.0", 14 | "pre-commit": "^1.2.2" 15 | }, 16 | "scripts": { 17 | "build": "make", 18 | "test": "make test", 19 | "lint": "./scripts/cpplint.py", 20 | "install": "node-gyp rebuild" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/bbondy/bloom-filter-cpp.git" 25 | }, 26 | "author": "Brian R. Bondy (http://www.brianbondy.com)", 27 | "license": "MPL-2.0", 28 | "gypfile": true, 29 | "bugs": { 30 | "url": "https://github.com/bbondy/bloom-filter-cpp/issues" 31 | }, 32 | "homepage": "https://github.com/bbondy/bloom-filter-cpp#readme", 33 | "pre-commit": [ 34 | "lint" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /scripts/cpplint.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import fnmatch 4 | import os 5 | import sys 6 | 7 | from lib.util import execute 8 | 9 | IGNORE_FILES = [ 10 | # os.path.join('./node_modules', 'nan', 'nan_implementation_12_inl.h') 11 | ] 12 | 13 | SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) 14 | 15 | 16 | def main(): 17 | os.chdir(SOURCE_ROOT) 18 | files = list_files([''], 19 | ['*.cpp', '*.cc', '*.h']) 20 | 21 | node_modules_files = list_files(['node_modules'], 22 | ['*.cpp', '*.cc', '*.h']) 23 | 24 | call_cpplint(list(set(files) - set(IGNORE_FILES) - set(node_modules_files))) 25 | 26 | 27 | def list_files(directories, filters): 28 | matches = [] 29 | for directory in directories: 30 | for root, _, filenames, in os.walk(os.path.join('./', directory)): 31 | for f in filters: 32 | for filename in fnmatch.filter(filenames, f): 33 | matches.append(os.path.join(root, filename)) 34 | return matches 35 | 36 | 37 | def call_cpplint(files): 38 | cpplint = os.path.join(SOURCE_ROOT, 'vendor', 'depot_tools', 'cpplint.py') 39 | execute([sys.executable, cpplint] + files) 40 | 41 | 42 | if __name__ == '__main__': 43 | sys.exit(main()) 44 | -------------------------------------------------------------------------------- /BloomFilterWrap.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef BLOOMFILTERWRAP_H_ 7 | #define BLOOMFILTERWRAP_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "BloomFilter.h" 13 | 14 | namespace BloomFilterWrap { 15 | 16 | /** 17 | * Wraps Bloom Filter for use in Node 18 | */ 19 | class BloomFilterWrap : public BloomFilter, public node::ObjectWrap { 20 | public: 21 | static void Init(v8::Local exports); 22 | 23 | private: 24 | BloomFilterWrap(unsigned int bitsPerElement = 10, 25 | unsigned int estimatedNumElements = 50000, 26 | HashFn hashFns[] = defaultHashFns, 27 | int numHashFns = sizeof(defaultHashFns)/sizeof(defaultHashFns[0])); 28 | virtual ~BloomFilterWrap(); 29 | 30 | static void New(const v8::FunctionCallbackInfo& args); 31 | 32 | static void Add(const v8::FunctionCallbackInfo& args); 33 | static void Exists(const v8::FunctionCallbackInfo& args); 34 | 35 | static v8::Persistent constructor; 36 | }; 37 | 38 | } // namespace BloomFilterWrap 39 | 40 | #endif // BLOOMFILTERWRAP_H_ 41 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | // List of configurations. Add new configurations or edit existing ones. 4 | "configurations": [ 5 | { 6 | // Name of configuration; appears in the launch configuration drop down menu. 7 | "name": "Launch app.js", 8 | // Type of configuration. 9 | "type": "node", 10 | // Workspace relative or absolute path to the program. 11 | "program": "app.js", 12 | // Automatically stop program after launch. 13 | "stopOnEntry": false, 14 | // Command line arguments passed to the program. 15 | "args": [], 16 | // Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace. 17 | "cwd": ".", 18 | // Workspace relative or absolute path to the runtime executable to be used. Default is the runtime executable on the PATH. 19 | "runtimeExecutable": null, 20 | // Optional arguments passed to the runtime executable. 21 | "runtimeArgs": ["--nolazy"], 22 | // Environment variables passed to the program. 23 | "env": { 24 | "NODE_ENV": "development" 25 | }, 26 | // Use JavaScript source maps (if they exist). 27 | "sourceMaps": false, 28 | // If JavaScript source maps are enabled, the generated code is expected in this directory. 29 | "outDir": null 30 | }, 31 | { 32 | "name": "Attach", 33 | "type": "node", 34 | // TCP/IP address. Default is "localhost". 35 | "address": "localhost", 36 | // Port to attach to. 37 | "port": 5858, 38 | "sourceMaps": false 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include "BloomFilter.h" 8 | 9 | using std::cout; 10 | using std::endl; 11 | 12 | char separatorBuffer[32] = { 0, 0, 0, 0, 0, -128, 0, -92, 0, 0, 0, 64 }; 13 | inline bool isSeparatorChar(char c) { 14 | return !!(separatorBuffer[c / 8] & 1 << c % 8); 15 | } 16 | 17 | int main(int argc, char**argv) { 18 | BloomFilter bloomFilter(8, 32); 19 | bloomFilter.setBit(static_cast(':')); 20 | bloomFilter.setBit(static_cast('?')); 21 | bloomFilter.setBit(static_cast('/')); 22 | bloomFilter.setBit(static_cast('=')); 23 | bloomFilter.setBit(static_cast('^')); 24 | cout << "size: " << bloomFilter.getByteBufferSize() << endl; 25 | for (int i = 0; i < bloomFilter.getByteBufferSize(); i++) { 26 | cout << " " << static_cast(bloomFilter.getBuffer()[i]); 27 | } 28 | cout << endl; 29 | 30 | cout << "Separator chars: " << isSeparatorChar(':') << " " 31 | << isSeparatorChar('?') << " " << isSeparatorChar('/') << " " 32 | << isSeparatorChar('=') << isSeparatorChar('^') << endl; 33 | 34 | cout << "NON Separator chars: " << isSeparatorChar('a') << " " 35 | << isSeparatorChar('!') << " " << isSeparatorChar('#') << " " 36 | << isSeparatorChar('X') << isSeparatorChar('.') 37 | << isSeparatorChar('\\') << isSeparatorChar('"') 38 | << isSeparatorChar(-128) << endl; 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /scripts/lib/config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import errno 4 | import os 5 | import platform 6 | import sys 7 | 8 | 9 | BASE_URL = os.getenv('LIBCHROMIUMCONTENT_MIRROR') or \ 10 | 'https://s3.amazonaws.com/github-janky-artifacts/libchromiumcontent' 11 | LIBCHROMIUMCONTENT_COMMIT = 'cfbe8ec7e14af4cabd1474386f54e197db1f7ac1' 12 | 13 | PLATFORM = { 14 | 'cygwin': 'win32', 15 | 'darwin': 'darwin', 16 | 'linux2': 'linux', 17 | 'win32': 'win32', 18 | }[sys.platform] 19 | 20 | verbose_mode = False 21 | 22 | 23 | def get_platform_key(): 24 | if os.environ.has_key('MAS_BUILD'): 25 | return 'mas' 26 | else: 27 | return PLATFORM 28 | 29 | 30 | def get_target_arch(): 31 | try: 32 | target_arch_path = os.path.join(__file__, '..', '..', '..', 'vendor', 33 | 'brightray', 'vendor', 'download', 34 | 'libchromiumcontent', '.target_arch') 35 | with open(os.path.normpath(target_arch_path)) as f: 36 | return f.read().strip() 37 | except IOError as e: 38 | if e.errno != errno.ENOENT: 39 | raise 40 | 41 | if PLATFORM == 'win32': 42 | return 'ia32' 43 | else: 44 | return 'x64' 45 | 46 | 47 | def get_chromedriver_version(): 48 | return 'v2.15' 49 | 50 | 51 | def s3_config(): 52 | config = (os.environ.get('ATOM_SHELL_S3_BUCKET', ''), 53 | os.environ.get('ATOM_SHELL_S3_ACCESS_KEY', ''), 54 | os.environ.get('ATOM_SHELL_S3_SECRET_KEY', '')) 55 | message = ('Error: Please set the $ATOM_SHELL_S3_BUCKET, ' 56 | '$ATOM_SHELL_S3_ACCESS_KEY, and ' 57 | '$ATOM_SHELL_S3_SECRET_KEY environment variables') 58 | assert all(len(c) for c in config), message 59 | return config 60 | 61 | 62 | def enable_verbose_mode(): 63 | print 'Running in verbose mode' 64 | global verbose_mode 65 | verbose_mode = True 66 | 67 | 68 | def is_verbose_mode(): 69 | return verbose_mode 70 | -------------------------------------------------------------------------------- /hashFn.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef HASHFN_H_ 7 | #define HASHFN_H_ 8 | 9 | #include "./base.h" 10 | 11 | typedef uint64_t uint64Array[30]; 12 | static int precomputedArraySize = sizeof(uint64Array) / sizeof(uint64_t); 13 | 14 | inline uint64_t customPow(uint64Array *precomputedPowers, bool usePrecomputed, 15 | uint64_t base, int exp) { 16 | if (usePrecomputed && exp < precomputedArraySize) { 17 | return (*precomputedPowers)[exp]; 18 | } 19 | 20 | // TOOD: Optimization possible here when passed in toSize which is bigger 21 | // than precomputedArraySize, we can start from the value of the last 22 | // precomputed value. 23 | uint64_t result = 1; 24 | while (exp) { 25 | if (exp & 1) 26 | result *= base; 27 | exp >>= 1; 28 | base *= base; 29 | } 30 | return result; 31 | } 32 | 33 | 34 | // Functor for a hashing function 35 | // Implements a Rabin fingerprint hash function 36 | class HashFn { 37 | public: 38 | // Initialize a HashFn with the prime p which is used as the base of the Rabin 39 | // fingerprint algorithm 40 | explicit HashFn(int p, bool precompute = true) { 41 | this->p = p; 42 | this->precompute = precompute; 43 | if (precompute) { 44 | uint64_t result = 1; 45 | for (int i = 0; i < precomputedArraySize; i++) { 46 | precomputedPowers[i] = result; 47 | result *= p; 48 | } 49 | } 50 | } 51 | 52 | virtual uint64_t operator()(const char *input, int len, 53 | unsigned char lastCharCode, uint64_t lastHash); 54 | 55 | virtual uint64_t operator()(const char *input, int len); 56 | 57 | private: 58 | int p; 59 | bool precompute; 60 | uint64Array precomputedPowers; 61 | }; 62 | 63 | #endif // HASHFN_H_ 64 | -------------------------------------------------------------------------------- /scripts/lib/github.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import json 4 | import os 5 | import re 6 | import sys 7 | 8 | REQUESTS_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', 9 | 'vendor', 'requests')) 10 | sys.path.append(os.path.join(REQUESTS_DIR, 'build', 'lib')) 11 | sys.path.append(os.path.join(REQUESTS_DIR, 'build', 'lib.linux-x86_64-2.7')) 12 | import requests 13 | 14 | GITHUB_URL = 'https://api.github.com' 15 | GITHUB_UPLOAD_ASSET_URL = 'https://uploads.github.com' 16 | 17 | class GitHub: 18 | def __init__(self, access_token): 19 | self._authorization = 'token %s' % access_token 20 | 21 | pattern = '^/repos/{0}/{0}/releases/{1}/assets$'.format('[^/]+', '[0-9]+') 22 | self._releases_upload_api_pattern = re.compile(pattern) 23 | 24 | def __getattr__(self, attr): 25 | return _Callable(self, '/%s' % attr) 26 | 27 | def send(self, method, path, **kw): 28 | if not 'headers' in kw: 29 | kw['headers'] = dict() 30 | headers = kw['headers'] 31 | headers['Authorization'] = self._authorization 32 | headers['Accept'] = 'application/vnd.github.manifold-preview' 33 | 34 | # Switch to a different domain for the releases uploading API. 35 | if self._releases_upload_api_pattern.match(path): 36 | url = '%s%s' % (GITHUB_UPLOAD_ASSET_URL, path) 37 | else: 38 | url = '%s%s' % (GITHUB_URL, path) 39 | # Data are sent in JSON format. 40 | if 'data' in kw: 41 | kw['data'] = json.dumps(kw['data']) 42 | 43 | r = getattr(requests, method)(url, **kw).json() 44 | if 'message' in r: 45 | raise Exception(json.dumps(r, indent=2, separators=(',', ': '))) 46 | return r 47 | 48 | 49 | class _Executable: 50 | def __init__(self, gh, method, path): 51 | self._gh = gh 52 | self._method = method 53 | self._path = path 54 | 55 | def __call__(self, **kw): 56 | return self._gh.send(self._method, self._path, **kw) 57 | 58 | 59 | class _Callable(object): 60 | def __init__(self, gh, name): 61 | self._gh = gh 62 | self._name = name 63 | 64 | def __call__(self, *args): 65 | if len(args) == 0: 66 | return self 67 | 68 | name = '%s/%s' % (self._name, '/'.join([str(arg) for arg in args])) 69 | return _Callable(self._gh, name) 70 | 71 | def __getattr__(self, attr): 72 | if attr in ['get', 'put', 'post', 'patch', 'delete']: 73 | return _Executable(self._gh, attr, self._name) 74 | 75 | name = '%s/%s' % (self._name, attr) 76 | return _Callable(self._gh, name) 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/bbondy/bloom-filter-cpp.svg?branch=master)](https://travis-ci.org/bbondy/bloom-filter-cpp) 2 | 3 | # BloomFilter.cpp 4 | C++ Native node module Bloom filter written in C++ for use in node or any other C++ project. 5 | 6 | The Bloom filter tests whether an element belongs to a set. False positive matches are possible but not common, false negatives are not possible. 7 | The Bloom filter library also implements Rabin–Karp algorithm with Rabin fingerprint hashes for multiple substring searches. 8 | 9 | This is a port of a [similar lib](https://github.com/bbondy/bloom-filter-js) I prototyped in JS. 10 | 11 | ## To include bloom-filter-cpp in your project: 12 | 13 | ``` 14 | npm install --save bloom-filter-cpp 15 | ``` 16 | 17 | 18 | ## JS Usage 19 | 20 | ```javascript 21 | var BloomFilter = require('bloom-filter-cpp').BloomFilter 22 | 23 | var b1 = new BloomFilter() 24 | 25 | console.log('b1 ading hello') 26 | b1.add('hello') 27 | 28 | console.log('b1 exists hello? ', b1.exists('hello')) 29 | console.log('b1 exists hello2? ', b1.exists('hello2')) 30 | 31 | var b2 = new BloomFilter() 32 | console.log('b2 exists hello? ', b2.exists('hello')) 33 | console.log('b2 exists hello2? ', b2.exists('hello2')) 34 | ``` 35 | 36 | 37 | ## C++ Usage 38 | 39 | ```c++ 40 | #include "BloomFilter.h" 41 | #include 42 | 43 | using namespace std; 44 | 45 | int main(int argc, char**argv) { 46 | BloomFilter b; 47 | b.add("Brian"); 48 | b.add("Ronald"); 49 | b.add("Bondy"); 50 | 51 | // Prints true 52 | cout << (b.exists("Brian") ? "true" : "false") << endl; 53 | 54 | // Prints false 55 | cout << (b.exists("Brian Ronald") ? "true" : "false") << endl; 56 | 57 | // Create a new BloomerFilter form a previous serialization 58 | BloomFilter b2(b.getBuffer(), b.getByteBufferSize()); 59 | 60 | // Prints the same as above 61 | cout << (b2.exists("Brian") ? "true" : "false") << endl; 62 | cout << (b2.exists("Brian Ronald") ? "true" : "false") << endl; 63 | 64 | // And you can check if any substring of a passed string exists 65 | // Prints true 66 | cout << (b.substringExists("Hello my name is Brian", 5) ? "true" : "false") << endl; 67 | // Prints false 68 | cout << (b.substringExists("Hello my name is Bri", 3) ? "true" : "false") << endl; 69 | 70 | return 0; 71 | } 72 | ``` 73 | 74 | 75 | ## Developing bloom-filter-cpp 76 | 77 | ```` 78 | git clone bloom-filter-cpp 79 | npm install 80 | ``` 81 | 82 | ## Build everything in release 83 | 84 | ``` 85 | make 86 | ``` 87 | 88 | ## Running sample 89 | 90 | ``` 91 | make sample 92 | ``` 93 | 94 | ## Running tests 95 | 96 | ``` 97 | make test 98 | ``` 99 | 100 | ## Clearing build files 101 | ``` 102 | make clean 103 | ``` 104 | -------------------------------------------------------------------------------- /BloomFilterWrap.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include "BloomFilterWrap.h" 7 | 8 | namespace BloomFilterWrap { 9 | 10 | using v8::Context; 11 | using v8::Function; 12 | using v8::FunctionCallbackInfo; 13 | using v8::FunctionTemplate; 14 | using v8::Isolate; 15 | using v8::Local; 16 | using v8::Number; 17 | using v8::Object; 18 | using v8::Persistent; 19 | using v8::String; 20 | using v8::Boolean; 21 | using v8::Value; 22 | 23 | Persistent BloomFilterWrap::constructor; 24 | 25 | BloomFilterWrap::BloomFilterWrap(unsigned int bitsPerElement, 26 | unsigned int estimatedNumElements, HashFn hashFns[], int numHashFns) 27 | : BloomFilter(bitsPerElement, estimatedNumElements, hashFns, numHashFns) { 28 | } 29 | 30 | BloomFilterWrap::~BloomFilterWrap() { 31 | } 32 | 33 | void BloomFilterWrap::Init(Local exports) { 34 | Isolate* isolate = exports->GetIsolate(); 35 | 36 | // Prepare constructor template 37 | Local tpl = FunctionTemplate::New(isolate, New); 38 | tpl->SetClassName(String::NewFromUtf8(isolate, "BloomFilter")); 39 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 40 | 41 | // Prototype 42 | NODE_SET_PROTOTYPE_METHOD(tpl, "add", BloomFilterWrap::Add); 43 | NODE_SET_PROTOTYPE_METHOD(tpl, "exists", BloomFilterWrap::Exists); 44 | 45 | constructor.Reset(isolate, tpl->GetFunction( 46 | isolate->GetCurrentContext()).ToLocalChecked()); 47 | exports->Set(String::NewFromUtf8(isolate, "BloomFilter"), 48 | tpl->GetFunction(isolate->GetCurrentContext()).ToLocalChecked()); 49 | } 50 | 51 | void BloomFilterWrap::New(const FunctionCallbackInfo& args) { 52 | Isolate* isolate = args.GetIsolate(); 53 | 54 | if (args.IsConstructCall()) { 55 | // Invoked as constructor: `new BloomFilter(...)` 56 | BloomFilterWrap* obj = new BloomFilterWrap(); 57 | obj->Wrap(args.This()); 58 | args.GetReturnValue().Set(args.This()); 59 | } else { 60 | // Invoked as plain function `BloomFilter(...)`, turn into construct call. 61 | const int argc = 1; 62 | Local argv[argc] = { args[0] }; 63 | Local context = isolate->GetCurrentContext(); 64 | Local cons = Local::New(isolate, constructor); 65 | Local result = 66 | cons->NewInstance(context, argc, argv).ToLocalChecked(); 67 | args.GetReturnValue().Set(result); 68 | } 69 | } 70 | 71 | void BloomFilterWrap::Add(const FunctionCallbackInfo& args) { 72 | Isolate* isolate = args.GetIsolate(); 73 | String::Utf8Value str(isolate, args[0]->ToString(isolate->GetCurrentContext()) 74 | .FromMaybe(v8::Local())); 75 | const char * buffer = *str; 76 | 77 | BloomFilterWrap* obj = ObjectWrap::Unwrap(args.Holder()); 78 | obj->add(buffer); 79 | } 80 | 81 | void BloomFilterWrap::Exists(const FunctionCallbackInfo& args) { 82 | Isolate* isolate = args.GetIsolate(); 83 | String::Utf8Value str(isolate, args[0]->ToString(isolate->GetCurrentContext()) 84 | .FromMaybe(v8::Local())); 85 | const char * buffer = *str; 86 | 87 | BloomFilterWrap* obj = ObjectWrap::Unwrap(args.Holder()); 88 | bool exists = obj->exists(buffer); 89 | 90 | args.GetReturnValue().Set(Boolean::New(isolate, exists)); 91 | } 92 | 93 | 94 | } // namespace BloomFilterWrap 95 | -------------------------------------------------------------------------------- /BloomFilter.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include "BloomFilter.h" 8 | 9 | BloomFilter::BloomFilter(unsigned int bitsPerElement, 10 | unsigned int estimatedNumElements, HashFn *hashFns, int numHashFns) : 11 | hashFns(nullptr), numHashFns(0), byteBufferSize(0), buffer(nullptr) { 12 | this->hashFns = hashFns; 13 | this->numHashFns = numHashFns; 14 | lastHashes = new uint64_t[numHashFns]; 15 | byteBufferSize = bitsPerElement * estimatedNumElements / 8 + 1; 16 | bitBufferSize = byteBufferSize * 8; 17 | buffer = new char[byteBufferSize]; 18 | memset(buffer, 0, byteBufferSize); 19 | } 20 | 21 | // Constructs a BloomFilter by copying the specified buffer and number of bytes 22 | BloomFilter::BloomFilter(const char *buffer, int byteBufferSize, 23 | HashFn *hashFns, int numHashFns) : 24 | hashFns(nullptr), numHashFns(0), byteBufferSize(0), buffer(nullptr) { 25 | this->hashFns = hashFns; 26 | this->numHashFns = numHashFns; 27 | lastHashes = new uint64_t[numHashFns]; 28 | this->byteBufferSize = byteBufferSize; 29 | bitBufferSize = byteBufferSize * 8; 30 | this->buffer = new char[byteBufferSize]; 31 | memcpy(this->buffer, buffer, byteBufferSize); 32 | } 33 | 34 | BloomFilter::~BloomFilter() { 35 | if (buffer) { 36 | delete[] buffer; 37 | } 38 | if (lastHashes) { 39 | delete[] lastHashes; 40 | } 41 | } 42 | 43 | void BloomFilter::setBit(unsigned int bitLocation) { 44 | buffer[bitLocation / 8] |= 1 << bitLocation % 8; 45 | } 46 | 47 | bool BloomFilter::isBitSet(unsigned int bitLocation) { 48 | return !!(buffer[bitLocation / 8] & 1 << bitLocation % 8); 49 | } 50 | 51 | void BloomFilter::add(const char *input, int len) { 52 | for (int j = 0; j < numHashFns; j++) { 53 | setBit(hashFns[j](input, len) % bitBufferSize); 54 | } 55 | } 56 | 57 | void BloomFilter::add(const char *sz) { 58 | add(sz, static_cast(strlen(sz))); 59 | } 60 | 61 | bool BloomFilter::exists(const char *input, int len) { 62 | bool allSet = true; 63 | for (int j = 0; j < numHashFns; j++) { 64 | allSet = allSet && isBitSet(hashFns[j](input, len) % bitBufferSize); 65 | } 66 | return allSet; 67 | } 68 | 69 | bool BloomFilter::exists(const char *sz) { 70 | return exists(sz, static_cast(strlen(sz))); 71 | } 72 | 73 | void BloomFilter::getHashesForCharCodes(const char *input, int inputLen, 74 | uint64_t *lastHashes, uint64_t *newHashes, unsigned char lastCharCode) { 75 | for (int i = 0; i < numHashFns; i++) { 76 | if (lastHashes) { 77 | *(newHashes + i) = hashFns[i](input, inputLen, 78 | lastCharCode, *(lastHashes+i)); 79 | } else { 80 | *(newHashes + i) = hashFns[i](input, inputLen); 81 | } 82 | } 83 | } 84 | 85 | bool BloomFilter::substringExists(const char *data, int dataLen, 86 | int substringLength) { 87 | unsigned char lastCharCode = 0; 88 | for (int i = 0; i < dataLen - substringLength + 1; i++) { 89 | getHashesForCharCodes(data + i, substringLength, i == 0 90 | ? nullptr : lastHashes, lastHashes, lastCharCode); 91 | bool allSet = true; 92 | for (int j = 0; j < numHashFns; j++) { 93 | allSet = allSet && isBitSet(lastHashes[j] % bitBufferSize); 94 | } 95 | if (allSet) { 96 | return true; 97 | } 98 | lastCharCode = data[i]; 99 | } 100 | return false; 101 | } 102 | 103 | bool BloomFilter::substringExists(const char *data, int substringLength) { 104 | return substringExists(data, static_cast(strlen(data)), substringLength); 105 | } 106 | 107 | void BloomFilter::clear() { 108 | memset(buffer, 0, byteBufferSize); 109 | } 110 | -------------------------------------------------------------------------------- /BloomFilter.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #ifndef BLOOMFILTER_H_ 7 | #define BLOOMFILTER_H_ 8 | 9 | #include 10 | #include 11 | #include "./hashFn.h" 12 | #include "./base.h" 13 | 14 | static HashFn h1(13); 15 | static HashFn h2(17); 16 | static HashFn h3(31); 17 | static HashFn h4(41); 18 | static HashFn h5(53); 19 | static HashFn defaultHashFns[5] = {h1, h2, h3, h4, h5}; 20 | 21 | 22 | /** 23 | * Implements a Bloom Filter using Rabin Karp for char* buffer lookups 24 | */ 25 | class BloomFilter { 26 | public: 27 | BloomFilter(unsigned int bitsPerElement = 10, 28 | unsigned int estimatedNumElements = 50000, 29 | HashFn hashFns[] = defaultHashFns, 30 | int numHashFns = sizeof(defaultHashFns)/sizeof(defaultHashFns[0])); 31 | BloomFilter(const char *buffer, int byteBufferSize, 32 | HashFn hashFns[] = defaultHashFns, 33 | int numHashFns = sizeof(defaultHashFns)/sizeof(defaultHashFns[0])); 34 | virtual ~BloomFilter(); 35 | // Sets the specified bit in the buffer 36 | void setBit(unsigned int bitLocation); 37 | // Checks if the specified bit is set in the buffer 38 | bool isBitSet(unsigned int bitLocation); 39 | // Adds the specified buffer to the bloom filter 40 | void add(const char *input, int len); 41 | void add(const char *sz); 42 | // Empty the Bloom Filter 43 | void clear(); 44 | 45 | /** 46 | * Checks whether an element probably exists in the set, or definitely 47 | * doesn't. 48 | * @param sz Either a string to check for existance or an array of the 49 | * string's char codes. The main reason why you'd want to pass in a char 50 | * code array is because passing a string will use JS directly to get 51 | * the char codes which is very inneficient compared to calling into C++ 52 | * code to get it and then making the call. 53 | * 54 | * Returns true if the element probably exists in the set 55 | * Returns false if the element definitely does not exist in the set 56 | */ 57 | bool exists(const char *input, int len); 58 | bool exists(const char *sz); 59 | 60 | /** 61 | * Checks if any substring of length substringLength probably exists or 62 | * definitely doesn't. If false is returned then no substring of the 63 | * specified string of the specified length is in the bloom filter 64 | * 65 | * @param data The substring or char array to check substrings on. 66 | */ 67 | bool substringExists(const char *data, int dataLen, int substringLength); 68 | bool substringExists(const char *sz, int substringLength); 69 | 70 | /** 71 | * Obtains the buffer used as the bloom filter data 72 | */ 73 | const char * getBuffer() { 74 | return buffer; 75 | } 76 | 77 | /** 78 | * Obtains the Bloom Filter's buffer size in bytes 79 | */ 80 | int getByteBufferSize() { 81 | return byteBufferSize; 82 | } 83 | 84 | private: 85 | HashFn *hashFns; 86 | uint64_t *lastHashes; 87 | int numHashFns; 88 | unsigned int byteBufferSize; 89 | unsigned int bitBufferSize; 90 | char *buffer; 91 | 92 | /** 93 | * Obtains the hashes for the specified charCodes 94 | * See "Rabin fingerprint" in 95 | * https://en.wikipedia.org/wiki/Rabin%E2%80%93Karp_algorithm 96 | * for more information. 97 | * 98 | * @param charCodes An array of the char codes to use for the hash 99 | * @param lastHashes Input and output for the last hash value 100 | * function for a faster computation. Must be called with lastCharCode but 101 | * can be nullptr otherwise. 102 | * 103 | * @param newHashses fills in the corresponding new hashes, can be the same 104 | * as lastHashes 105 | * @param lastCharCode if specified, it will pass the last char code 106 | * to the hashing function for a faster computation. Must be called 107 | * with lastHashes. 108 | */ 109 | void getHashesForCharCodes(const char *input, int inputLen, 110 | uint64_t *lastHashes, uint64_t *newHashes, unsigned char lastCharCode); 111 | }; 112 | 113 | #endif // BLOOMFILTER_H_ 114 | -------------------------------------------------------------------------------- /test/test-bloom.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2015 Brian R. Bondy. Distributed under the MPL2 license. 2 | * This Source Code Form is subject to the terms of the Mozilla Public 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "./CppUnitLite/TestHarness.h" 15 | #include "./CppUnitLite/Test.h" 16 | #include "./BloomFilter.h" 17 | #include "./util.h" 18 | 19 | TEST(BloomFilter, isBitSetSetBit) { 20 | BloomFilter b(10, 3); 21 | 22 | // First bit in a byte 23 | CHECK(!b.isBitSet(0)) 24 | b.setBit(0); 25 | CHECK(b.isBitSet(0)) 26 | 27 | // Last bit in a byte 28 | CHECK(!b.isBitSet(7)) 29 | b.setBit(7); 30 | CHECK(b.isBitSet(7)) 31 | for (int i = 1; i <= 6; i++) { 32 | CHECK(!b.isBitSet(i)); 33 | } 34 | CHECK(b.isBitSet(0)); 35 | 36 | // Second bit in non first byte 37 | CHECK(!b.isBitSet(9)) 38 | b.setBit(9); 39 | CHECK(b.isBitSet(9)) 40 | CHECK(!b.isBitSet(1)); 41 | } 42 | 43 | // Generates a simple hash function for the specified prime 44 | TEST(BloomFilter, SimpleHashFn) { 45 | HashFn h(2); 46 | uint64_t hash = h("hi", 2); 47 | CHECK(hash == (static_cast('h')) * pow(2, 1) + 48 | static_cast('i') * pow(2, 0)); 49 | 50 | { 51 | HashFn h(19, false); 52 | HashFn h2(19, true); 53 | const char *sz = "facebook.com"; 54 | const char *sz2 = "abcde"; 55 | LONGS_EQUAL(h(sz, strlen(sz)), 12510474367240317); 56 | LONGS_EQUAL(h2(sz, strlen(sz)), 12510474367240317); 57 | LONGS_EQUAL(h(sz2, strlen(sz2)), 13351059); 58 | LONGS_EQUAL(h2(sz2, strlen(sz2)), 13351059); 59 | } 60 | } 61 | 62 | // Detects when elements are in the set and not in the set 63 | TEST(BloomFilter, Basic) { 64 | BloomFilter b; 65 | b.add("Brian"); 66 | b.add("Ronald"); 67 | b.add("Bondy"); 68 | CHECK(b.exists("Brian")); 69 | CHECK(!b.exists("Brian2")); 70 | CHECK(!b.exists("Bria")); 71 | 72 | CHECK(b.exists("Ronald")); 73 | CHECK(!b.exists("Ronald2")); 74 | CHECK(!b.exists("onald2")); 75 | 76 | CHECK(b.exists("Bondy")); 77 | CHECK(!b.exists("BrianRonaldBondy")); 78 | CHECK(!b.exists("RonaldBondy")); 79 | } 80 | 81 | void genRandomBuffer(char *s, const int len) { 82 | for (int i = 0; i < len; ++i) { 83 | s[i] = rand() % 256; // NOLINT 84 | } 85 | s[len - 1] = 0; 86 | } 87 | 88 | // Can handle long strings 89 | TEST(BloomFilter, BasicLongStrings) { 90 | const int kBufSize = 20000; 91 | char id1[kBufSize]; 92 | char id2[kBufSize]; 93 | char id3[kBufSize]; 94 | genRandomBuffer(id1, kBufSize); 95 | genRandomBuffer(id2, kBufSize); 96 | genRandomBuffer(id3, kBufSize); 97 | 98 | HashFn h1 = HashFn(0); 99 | HashFn h2 = HashFn(1023); 100 | HashFn hashFns[2] = {h1, h2}; 101 | 102 | BloomFilter b(10, 5000, hashFns, sizeof(hashFns)/sizeof(hashFns[0])); 103 | 104 | b.add(id1, kBufSize); 105 | b.add(id2, kBufSize); 106 | CHECK(b.exists(id1, kBufSize)); 107 | CHECK(b.exists(id2, kBufSize)); 108 | CHECK(!b.exists("hello")); 109 | CHECK(!b.exists(id3, kBufSize)); 110 | } 111 | 112 | // supports substringExists 113 | TEST(BloomFilter, substringExists) { 114 | BloomFilter b; 115 | b.add("abc"); 116 | b.add("hello"); 117 | b.add("world"); 118 | CHECK(b.substringExists("hello", 5)); 119 | // Only substrings of length 5 should exist in the bloom filter 120 | CHECK(!b.substringExists("ell", 3)); 121 | CHECK(b.substringExists("wow ok hello!!!!", 5)); 122 | CHECK(!b.substringExists("he!lloworl!d", 5)); 123 | } 124 | 125 | // Can return false positives for a saturated set 126 | TEST(BloomFilter, falsePositives) { 127 | BloomFilter b(2, 2); 128 | char sz[64]; 129 | for (int i = 0; i < 100; i++) { 130 | snprintf(sz, sizeof(sz), "test-%i", i); 131 | b.add(sz); 132 | } 133 | CHECK(b.exists("test")); 134 | } 135 | 136 | // It cannot return false negatives 137 | TEST(BloomFilter, noFalseNegatives) { 138 | BloomFilter b; 139 | char sz[64]; 140 | for (int i = 0; i < 100000; i++) { 141 | snprintf(sz, sizeof(sz), "test-%i", i); 142 | b.add(sz); 143 | } 144 | for (int i = 0; i < 100000; i++) { 145 | snprintf(sz, sizeof(sz), "test-%i", i); 146 | CHECK(b.exists(sz)); 147 | } 148 | } 149 | 150 | // Works with some live examples 151 | TEST(BloomFilter, liveExamples) { 152 | BloomFilter b; 153 | b.add("googlesy"); 154 | const char *url1 = 155 | "http://tpc.googlesyndication.com/safeframe/1-0-2/html/container.html#" 156 | "xpc=sf-gdn-exp-2&p=http%3A//slashdot.org"; 157 | const char *url2 = 158 | "https://tpc.googlesyndication.com/pagead/gadgets/suggestion_autolayout_V2/" 159 | "suggestion_autolayout_V2.html#t=15174732506449260991&p=http%3A%2F%2F" 160 | "tpc.googlesyndication.com"; 161 | CHECK(b.substringExists("googlesy", 8)); 162 | CHECK(b.substringExists(url1, 8)); 163 | CHECK(b.substringExists(url2, 8)); 164 | } 165 | 166 | // Works by transfering a buffer 167 | TEST(BloomFilter, transferingBuffer) { 168 | BloomFilter b; 169 | b.add("Brian"); 170 | b.add("Ronald"); 171 | b.add("Bondy"); 172 | 173 | BloomFilter b2(b.getBuffer(), b.getByteBufferSize()); 174 | CHECK(b2.exists("Brian")); 175 | CHECK(!b2.exists("Brian2")); 176 | CHECK(!b2.exists("Bria")); 177 | 178 | CHECK(b2.exists("Ronald")); 179 | CHECK(!b2.exists("Ronald2")); 180 | CHECK(!b2.exists("onald2")); 181 | 182 | CHECK(b2.exists("Bondy")); 183 | CHECK(!b2.exists("BrianRonaldBondy")); 184 | CHECK(!b2.exists("RonaldBondy")); 185 | } 186 | 187 | // Works by transfering a buffer 188 | TEST(BloomFilter, clearBloomFilter) { 189 | BloomFilter b; 190 | b.add("Brian"); 191 | CHECK(b.exists("Brian")); 192 | b.clear(); 193 | CHECK(!b.exists("Brian")); 194 | } 195 | -------------------------------------------------------------------------------- /scripts/lib/util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import atexit 4 | import contextlib 5 | import errno 6 | import platform 7 | import re 8 | import shutil 9 | import ssl 10 | import subprocess 11 | import sys 12 | import tarfile 13 | import tempfile 14 | import urllib2 15 | import os 16 | import zipfile 17 | 18 | from config import is_verbose_mode 19 | 20 | 21 | def get_host_arch(): 22 | """Returns the host architecture with a predictable string.""" 23 | host_arch = platform.machine() 24 | 25 | # Convert machine type to format recognized by gyp. 26 | if re.match(r'i.86', host_arch) or host_arch == 'i86pc': 27 | host_arch = 'ia32' 28 | elif host_arch in ['x86_64', 'amd64']: 29 | host_arch = 'x64' 30 | elif host_arch.startswith('arm'): 31 | host_arch = 'arm' 32 | 33 | # platform.machine is based on running kernel. It's possible to use 64-bit 34 | # kernel with 32-bit userland, e.g. to give linker slightly more memory. 35 | # Distinguish between different userland bitness by querying 36 | # the python binary. 37 | if host_arch == 'x64' and platform.architecture()[0] == '32bit': 38 | host_arch = 'ia32' 39 | 40 | return host_arch 41 | 42 | 43 | def tempdir(prefix=''): 44 | directory = tempfile.mkdtemp(prefix=prefix) 45 | atexit.register(shutil.rmtree, directory) 46 | return directory 47 | 48 | 49 | @contextlib.contextmanager 50 | def scoped_cwd(path): 51 | cwd = os.getcwd() 52 | os.chdir(path) 53 | try: 54 | yield 55 | finally: 56 | os.chdir(cwd) 57 | 58 | 59 | @contextlib.contextmanager 60 | def scoped_env(key, value): 61 | origin = '' 62 | if key in os.environ: 63 | origin = os.environ[key] 64 | os.environ[key] = value 65 | try: 66 | yield 67 | finally: 68 | os.environ[key] = origin 69 | 70 | 71 | def download(text, url, path): 72 | safe_mkdir(os.path.dirname(path)) 73 | with open(path, 'wb') as local_file: 74 | if hasattr(ssl, '_create_unverified_context'): 75 | ssl._create_default_https_context = ssl._create_unverified_context 76 | 77 | web_file = urllib2.urlopen(url) 78 | file_size = int(web_file.info().getheaders("Content-Length")[0]) 79 | downloaded_size = 0 80 | block_size = 128 81 | 82 | ci = os.environ.get('CI') == '1' 83 | 84 | while True: 85 | buf = web_file.read(block_size) 86 | if not buf: 87 | break 88 | 89 | downloaded_size += len(buf) 90 | local_file.write(buf) 91 | 92 | if not ci: 93 | percent = downloaded_size * 100. / file_size 94 | status = "\r%s %10d [%3.1f%%]" % (text, downloaded_size, percent) 95 | print status, 96 | 97 | if ci: 98 | print "%s done." % (text) 99 | else: 100 | print 101 | return path 102 | 103 | 104 | def extract_tarball(tarball_path, member, destination): 105 | with tarfile.open(tarball_path) as tarball: 106 | tarball.extract(member, destination) 107 | 108 | 109 | def extract_zip(zip_path, destination): 110 | if sys.platform == 'darwin': 111 | # Use unzip command on Mac to keep symbol links in zip file work. 112 | execute(['unzip', zip_path, '-d', destination]) 113 | else: 114 | with zipfile.ZipFile(zip_path) as z: 115 | z.extractall(destination) 116 | 117 | def make_zip(zip_file_path, files, dirs): 118 | safe_unlink(zip_file_path) 119 | if sys.platform == 'darwin': 120 | files += dirs 121 | execute(['zip', '-r', '-y', zip_file_path] + files) 122 | else: 123 | zip_file = zipfile.ZipFile(zip_file_path, "w", zipfile.ZIP_DEFLATED) 124 | for filename in files: 125 | zip_file.write(filename, filename) 126 | for dirname in dirs: 127 | for root, _, filenames in os.walk(dirname): 128 | for f in filenames: 129 | zip_file.write(os.path.join(root, f)) 130 | zip_file.close() 131 | 132 | 133 | def rm_rf(path): 134 | try: 135 | shutil.rmtree(path) 136 | except OSError: 137 | pass 138 | 139 | 140 | def safe_unlink(path): 141 | try: 142 | os.unlink(path) 143 | except OSError as e: 144 | if e.errno != errno.ENOENT: 145 | raise 146 | 147 | 148 | def safe_mkdir(path): 149 | try: 150 | os.makedirs(path) 151 | except OSError as e: 152 | if e.errno != errno.EEXIST: 153 | raise 154 | 155 | 156 | def execute(argv, env=os.environ): 157 | if is_verbose_mode(): 158 | print ' '.join(argv) 159 | try: 160 | output = subprocess.check_output(argv, stderr=subprocess.STDOUT, env=env) 161 | if is_verbose_mode(): 162 | print output 163 | return output 164 | except subprocess.CalledProcessError as e: 165 | print e.output 166 | raise e 167 | 168 | 169 | def execute_stdout(argv, env=os.environ): 170 | if is_verbose_mode(): 171 | print ' '.join(argv) 172 | try: 173 | subprocess.check_call(argv, env=env) 174 | except subprocess.CalledProcessError as e: 175 | print e.output 176 | raise e 177 | else: 178 | execute(argv, env) 179 | 180 | 181 | def atom_gyp(): 182 | SOURCE_ROOT = os.path.abspath(os.path.join(__file__, '..', '..', '..')) 183 | gyp = os.path.join(SOURCE_ROOT, 'atom.gyp') 184 | with open(gyp) as f: 185 | obj = eval(f.read()); 186 | return obj['variables'] 187 | 188 | 189 | def get_atom_shell_version(): 190 | return 'v' + atom_gyp()['version%'] 191 | 192 | 193 | def parse_version(version): 194 | if version[0] == 'v': 195 | version = version[1:] 196 | 197 | vs = version.split('.') 198 | if len(vs) > 4: 199 | return vs[0:4] 200 | else: 201 | return vs + ['0'] * (4 - len(vs)) 202 | 203 | 204 | def s3put(bucket, access_key, secret_key, prefix, key_prefix, files): 205 | env = os.environ.copy() 206 | BOTO_DIR = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'vendor', 207 | 'boto')) 208 | env['PYTHONPATH'] = os.path.pathsep.join([ 209 | env.get('PYTHONPATH', ''), 210 | os.path.join(BOTO_DIR, 'build', 'lib'), 211 | os.path.join(BOTO_DIR, 'build', 'lib.linux-x86_64-2.7')]) 212 | 213 | boto = os.path.join(BOTO_DIR, 'bin', 's3put') 214 | args = [ 215 | sys.executable, 216 | boto, 217 | '--bucket', bucket, 218 | '--access_key', access_key, 219 | '--secret_key', secret_key, 220 | '--prefix', prefix, 221 | '--key_prefix', key_prefix, 222 | '--grant', 'public-read' 223 | ] + files 224 | 225 | execute(args, env) 226 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License, version 2.0 2 | 3 | 1. Definitions 4 | 5 | 1.1. "Contributor" 6 | 7 | means each individual or legal entity that creates, contributes to the 8 | creation of, or owns Covered Software. 9 | 10 | 1.2. "Contributor Version" 11 | 12 | means the combination of the Contributions of others (if any) used by a 13 | Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | 17 | means Covered Software of a particular Contributor. 18 | 19 | 1.4. "Covered Software" 20 | 21 | means Source Code Form to which the initial Contributor has attached the 22 | notice in Exhibit A, the Executable Form of such Source Code Form, and 23 | Modifications of such Source Code Form, in each case including portions 24 | thereof. 25 | 26 | 1.5. "Incompatible With Secondary Licenses" 27 | means 28 | 29 | a. that the initial Contributor has attached the notice described in 30 | Exhibit B to the Covered Software; or 31 | 32 | b. that the Covered Software was made available under the terms of 33 | version 1.1 or earlier of the License, but not also under the terms of 34 | a Secondary License. 35 | 36 | 1.6. "Executable Form" 37 | 38 | means any form of the work other than Source Code Form. 39 | 40 | 1.7. "Larger Work" 41 | 42 | means a work that combines Covered Software with other material, in a 43 | separate file or files, that is not Covered Software. 44 | 45 | 1.8. "License" 46 | 47 | means this document. 48 | 49 | 1.9. "Licensable" 50 | 51 | means having the right to grant, to the maximum extent possible, whether 52 | at the time of the initial grant or subsequently, any and all of the 53 | rights conveyed by this License. 54 | 55 | 1.10. "Modifications" 56 | 57 | means any of the following: 58 | 59 | a. any file in Source Code Form that results from an addition to, 60 | deletion from, or modification of the contents of Covered Software; or 61 | 62 | b. any new file in Source Code Form that contains any Covered Software. 63 | 64 | 1.11. "Patent Claims" of a Contributor 65 | 66 | means any patent claim(s), including without limitation, method, 67 | process, and apparatus claims, in any patent Licensable by such 68 | Contributor that would be infringed, but for the grant of the License, 69 | by the making, using, selling, offering for sale, having made, import, 70 | or transfer of either its Contributions or its Contributor Version. 71 | 72 | 1.12. "Secondary License" 73 | 74 | means either the GNU General Public License, Version 2.0, the GNU Lesser 75 | General Public License, Version 2.1, the GNU Affero General Public 76 | License, Version 3.0, or any later versions of those licenses. 77 | 78 | 1.13. "Source Code Form" 79 | 80 | means the form of the work preferred for making modifications. 81 | 82 | 1.14. "You" (or "Your") 83 | 84 | means an individual or a legal entity exercising rights under this 85 | License. For legal entities, "You" includes any entity that controls, is 86 | controlled by, or is under common control with You. For purposes of this 87 | definition, "control" means (a) the power, direct or indirect, to cause 88 | the direction or management of such entity, whether by contract or 89 | otherwise, or (b) ownership of more than fifty percent (50%) of the 90 | outstanding shares or beneficial ownership of such entity. 91 | 92 | 93 | 2. License Grants and Conditions 94 | 95 | 2.1. Grants 96 | 97 | Each Contributor hereby grants You a world-wide, royalty-free, 98 | non-exclusive license: 99 | 100 | a. under intellectual property rights (other than patent or trademark) 101 | Licensable by such Contributor to use, reproduce, make available, 102 | modify, display, perform, distribute, and otherwise exploit its 103 | Contributions, either on an unmodified basis, with Modifications, or 104 | as part of a Larger Work; and 105 | 106 | b. under Patent Claims of such Contributor to make, use, sell, offer for 107 | sale, have made, import, and otherwise transfer either its 108 | Contributions or its Contributor Version. 109 | 110 | 2.2. Effective Date 111 | 112 | The licenses granted in Section 2.1 with respect to any Contribution 113 | become effective for each Contribution on the date the Contributor first 114 | distributes such Contribution. 115 | 116 | 2.3. Limitations on Grant Scope 117 | 118 | The licenses granted in this Section 2 are the only rights granted under 119 | this License. No additional rights or licenses will be implied from the 120 | distribution or licensing of Covered Software under this License. 121 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 122 | Contributor: 123 | 124 | a. for any code that a Contributor has removed from Covered Software; or 125 | 126 | b. for infringements caused by: (i) Your and any other third party's 127 | modifications of Covered Software, or (ii) the combination of its 128 | Contributions with other software (except as part of its Contributor 129 | Version); or 130 | 131 | c. under Patent Claims infringed by Covered Software in the absence of 132 | its Contributions. 133 | 134 | This License does not grant any rights in the trademarks, service marks, 135 | or logos of any Contributor (except as may be necessary to comply with 136 | the notice requirements in Section 3.4). 137 | 138 | 2.4. Subsequent Licenses 139 | 140 | No Contributor makes additional grants as a result of Your choice to 141 | distribute the Covered Software under a subsequent version of this 142 | License (see Section 10.2) or under the terms of a Secondary License (if 143 | permitted under the terms of Section 3.3). 144 | 145 | 2.5. Representation 146 | 147 | Each Contributor represents that the Contributor believes its 148 | Contributions are its original creation(s) or it has sufficient rights to 149 | grant the rights to its Contributions conveyed by this License. 150 | 151 | 2.6. Fair Use 152 | 153 | This License is not intended to limit any rights You have under 154 | applicable copyright doctrines of fair use, fair dealing, or other 155 | equivalents. 156 | 157 | 2.7. Conditions 158 | 159 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in 160 | Section 2.1. 161 | 162 | 163 | 3. Responsibilities 164 | 165 | 3.1. Distribution of Source Form 166 | 167 | All distribution of Covered Software in Source Code Form, including any 168 | Modifications that You create or to which You contribute, must be under 169 | the terms of this License. You must inform recipients that the Source 170 | Code Form of the Covered Software is governed by the terms of this 171 | License, and how they can obtain a copy of this License. You may not 172 | attempt to alter or restrict the recipients' rights in the Source Code 173 | Form. 174 | 175 | 3.2. Distribution of Executable Form 176 | 177 | If You distribute Covered Software in Executable Form then: 178 | 179 | a. such Covered Software must also be made available in Source Code Form, 180 | as described in Section 3.1, and You must inform recipients of the 181 | Executable Form how they can obtain a copy of such Source Code Form by 182 | reasonable means in a timely manner, at a charge no more than the cost 183 | of distribution to the recipient; and 184 | 185 | b. You may distribute such Executable Form under the terms of this 186 | License, or sublicense it under different terms, provided that the 187 | license for the Executable Form does not attempt to limit or alter the 188 | recipients' rights in the Source Code Form under this License. 189 | 190 | 3.3. Distribution of a Larger Work 191 | 192 | You may create and distribute a Larger Work under terms of Your choice, 193 | provided that You also comply with the requirements of this License for 194 | the Covered Software. If the Larger Work is a combination of Covered 195 | Software with a work governed by one or more Secondary Licenses, and the 196 | Covered Software is not Incompatible With Secondary Licenses, this 197 | License permits You to additionally distribute such Covered Software 198 | under the terms of such Secondary License(s), so that the recipient of 199 | the Larger Work may, at their option, further distribute the Covered 200 | Software under the terms of either this License or such Secondary 201 | License(s). 202 | 203 | 3.4. Notices 204 | 205 | You may not remove or alter the substance of any license notices 206 | (including copyright notices, patent notices, disclaimers of warranty, or 207 | limitations of liability) contained within the Source Code Form of the 208 | Covered Software, except that You may alter any license notices to the 209 | extent required to remedy known factual inaccuracies. 210 | 211 | 3.5. Application of Additional Terms 212 | 213 | You may choose to offer, and to charge a fee for, warranty, support, 214 | indemnity or liability obligations to one or more recipients of Covered 215 | Software. However, You may do so only on Your own behalf, and not on 216 | behalf of any Contributor. You must make it absolutely clear that any 217 | such warranty, support, indemnity, or liability obligation is offered by 218 | You alone, and You hereby agree to indemnify every Contributor for any 219 | liability incurred by such Contributor as a result of warranty, support, 220 | indemnity or liability terms You offer. You may include additional 221 | disclaimers of warranty and limitations of liability specific to any 222 | jurisdiction. 223 | 224 | 4. Inability to Comply Due to Statute or Regulation 225 | 226 | If it is impossible for You to comply with any of the terms of this License 227 | with respect to some or all of the Covered Software due to statute, 228 | judicial order, or regulation then You must: (a) comply with the terms of 229 | this License to the maximum extent possible; and (b) describe the 230 | limitations and the code they affect. Such description must be placed in a 231 | text file included with all distributions of the Covered Software under 232 | this License. Except to the extent prohibited by statute or regulation, 233 | such description must be sufficiently detailed for a recipient of ordinary 234 | skill to be able to understand it. 235 | 236 | 5. Termination 237 | 238 | 5.1. The rights granted under this License will terminate automatically if You 239 | fail to comply with any of its terms. However, if You become compliant, 240 | then the rights granted under this License from a particular Contributor 241 | are reinstated (a) provisionally, unless and until such Contributor 242 | explicitly and finally terminates Your grants, and (b) on an ongoing 243 | basis, if such Contributor fails to notify You of the non-compliance by 244 | some reasonable means prior to 60 days after You have come back into 245 | compliance. Moreover, Your grants from a particular Contributor are 246 | reinstated on an ongoing basis if such Contributor notifies You of the 247 | non-compliance by some reasonable means, this is the first time You have 248 | received notice of non-compliance with this License from such 249 | Contributor, and You become compliant prior to 30 days after Your receipt 250 | of the notice. 251 | 252 | 5.2. If You initiate litigation against any entity by asserting a patent 253 | infringement claim (excluding declaratory judgment actions, 254 | counter-claims, and cross-claims) alleging that a Contributor Version 255 | directly or indirectly infringes any patent, then the rights granted to 256 | You by any and all Contributors for the Covered Software under Section 257 | 2.1 of this License shall terminate. 258 | 259 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user 260 | license agreements (excluding distributors and resellers) which have been 261 | validly granted by You or Your distributors under this License prior to 262 | termination shall survive termination. 263 | 264 | 6. Disclaimer of Warranty 265 | 266 | Covered Software is provided under this License on an "as is" basis, 267 | without warranty of any kind, either expressed, implied, or statutory, 268 | including, without limitation, warranties that the Covered Software is free 269 | of defects, merchantable, fit for a particular purpose or non-infringing. 270 | The entire risk as to the quality and performance of the Covered Software 271 | is with You. Should any Covered Software prove defective in any respect, 272 | You (not any Contributor) assume the cost of any necessary servicing, 273 | repair, or correction. This disclaimer of warranty constitutes an essential 274 | part of this License. No use of any Covered Software is authorized under 275 | this License except under this disclaimer. 276 | 277 | 7. Limitation of Liability 278 | 279 | Under no circumstances and under no legal theory, whether tort (including 280 | negligence), contract, or otherwise, shall any Contributor, or anyone who 281 | distributes Covered Software as permitted above, be liable to You for any 282 | direct, indirect, special, incidental, or consequential damages of any 283 | character including, without limitation, damages for lost profits, loss of 284 | goodwill, work stoppage, computer failure or malfunction, or any and all 285 | other commercial damages or losses, even if such party shall have been 286 | informed of the possibility of such damages. This limitation of liability 287 | shall not apply to liability for death or personal injury resulting from 288 | such party's negligence to the extent applicable law prohibits such 289 | limitation. Some jurisdictions do not allow the exclusion or limitation of 290 | incidental or consequential damages, so this exclusion and limitation may 291 | not apply to You. 292 | 293 | 8. Litigation 294 | 295 | Any litigation relating to this License may be brought only in the courts 296 | of a jurisdiction where the defendant maintains its principal place of 297 | business and such litigation shall be governed by laws of that 298 | jurisdiction, without reference to its conflict-of-law provisions. Nothing 299 | in this Section shall prevent a party's ability to bring cross-claims or 300 | counter-claims. 301 | 302 | 9. Miscellaneous 303 | 304 | This License represents the complete agreement concerning the subject 305 | matter hereof. If any provision of this License is held to be 306 | unenforceable, such provision shall be reformed only to the extent 307 | necessary to make it enforceable. Any law or regulation which provides that 308 | the language of a contract shall be construed against the drafter shall not 309 | be used to construe this License against a Contributor. 310 | 311 | 312 | 10. Versions of the License 313 | 314 | 10.1. New Versions 315 | 316 | Mozilla Foundation is the license steward. Except as provided in Section 317 | 10.3, no one other than the license steward has the right to modify or 318 | publish new versions of this License. Each version will be given a 319 | distinguishing version number. 320 | 321 | 10.2. Effect of New Versions 322 | 323 | You may distribute the Covered Software under the terms of the version 324 | of the License under which You originally received the Covered Software, 325 | or under the terms of any subsequent version published by the license 326 | steward. 327 | 328 | 10.3. Modified Versions 329 | 330 | If you create software not governed by this License, and you want to 331 | create a new license for such software, you may create and use a 332 | modified version of this License if you rename the license and remove 333 | any references to the name of the license steward (except to note that 334 | such modified license differs from this License). 335 | 336 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 337 | Licenses If You choose to distribute Source Code Form that is 338 | Incompatible With Secondary Licenses under the terms of this version of 339 | the License, the notice described in Exhibit B of this License must be 340 | attached. 341 | 342 | Exhibit A - Source Code Form License Notice 343 | 344 | This Source Code Form is subject to the 345 | terms of the Mozilla Public License, v. 346 | 2.0. If a copy of the MPL was not 347 | distributed with this file, You can 348 | obtain one at 349 | http://mozilla.org/MPL/2.0/. 350 | 351 | If it is not possible or desirable to put the notice in a particular file, 352 | then You may include the notice in a location (such as a LICENSE file in a 353 | relevant directory) where a recipient would be likely to look for such a 354 | notice. 355 | 356 | You may add additional accurate notices of copyright ownership. 357 | 358 | Exhibit B - "Incompatible With Secondary Licenses" Notice 359 | 360 | This Source Code Form is "Incompatible 361 | With Secondary Licenses", as defined by 362 | the Mozilla Public License, v. 2.0. 363 | 364 | --------------------------------------------------------------------------------