├── .bowerrc ├── .gitignore ├── Gruntfile.js ├── LICENSE ├── LucenePlusPlusCMakeLists.txt.appveyor ├── README.md ├── app ├── app.js ├── css │ ├── 2fcrYFNaTjcS6g4U3t-Y5UEw0lE80llgEseQY3FEmqw.woff2 │ ├── icons.png │ ├── icons@2x.png │ ├── main.css │ ├── zest-devdocs.css │ └── zest-devdocs.css.scss ├── example.config.json ├── img │ ├── logo.icns │ ├── logo.ico │ └── logo_96x96.png ├── index.html ├── package.json ├── prod.config.json ├── sotags.json ├── templates │ ├── comments.handlebars │ └── post.handlebars ├── viewer.html └── viewer.js ├── appveyor.yml ├── binding.gyp ├── binding.gyp.appveyor ├── bower.json ├── circle.yml ├── env ├── dev │ └── cljs │ │ └── zest │ │ └── dev.cljs └── prod │ └── cljs │ └── zest │ └── prod.cljs ├── externs └── misc.js ├── nodelucene ├── CMakeLists.txt ├── CMakeLists.txt.appveyor ├── LuceneIndex.cc ├── LuceneIndex.h └── searcher.cc ├── package.json ├── packages.config ├── project.clj ├── scripts ├── build-windows-exe.nsi ├── build_app.bat ├── build_circle.sh ├── build_circle_deps.sh ├── build_deps.bat ├── dmg │ ├── TestBkg.png │ └── TestBkg@2x.png ├── setup.bat └── setup.sh ├── sogrep-src ├── CMakeLists.txt ├── CMakeLists.txt.appveyor ├── extractor.cpp ├── grep_python.py └── main.cpp ├── sqlite_score └── score.c └── src └── cljs └── zest ├── core.cljs ├── docs ├── devdocs.cljs ├── registry.cljs └── stackoverflow.cljs ├── searcher.cljs └── settings.cljs /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory" : "app/components" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /target 3 | /classes 4 | /checkouts 5 | pom.xml 6 | pom.xml.asc 7 | figwheel_server.log 8 | *.jar 9 | *.class 10 | /.lein-* 11 | /.nrepl- 12 | /app/js/p 13 | /.repl 14 | /out 15 | node_modules 16 | /electron 17 | /app/config.json 18 | /app/*.log 19 | /builds 20 | /app/components 21 | .nrepl-port 22 | /spec/static/test.js 23 | /.repl* 24 | *-init.clj 25 | .idea 26 | *.iml 27 | SearchIndex 28 | app/build 29 | sogrep-src/extractor 30 | sogrep-src/sogrep 31 | sogrep-src/Makefile 32 | nodelucene/searcher 33 | nodelucene/Makefile 34 | *.exe 35 | *.dll 36 | *.lib 37 | *.exp 38 | *.obj 39 | *.dir 40 | *.vcxproj 41 | *.vcxproj.filters 42 | *.sln 43 | *.sdf 44 | *.opendb 45 | extractor 46 | sogrep 47 | searcher 48 | CMakeFiles 49 | CMakeCache.txt 50 | cmake_install.cmake 51 | build 52 | app/SOPython 53 | sqlite_score/zest_score.sqlext 54 | sogrep-src/x64 55 | nodelucene/x64 56 | bzip2.v120.1.0.6.2 57 | LevelDB.1.16.0.5 58 | LucenePlusPlus 59 | Microsoft 60 | node-sqlite3 61 | rapidjson.1.0.2 62 | zlib-1.2.8 63 | zlib-1.2.8.tar 64 | xercesc.3.1.1 65 | xercesc.redist.3.1.1 66 | libarchive 67 | lein.bat 68 | electron-v*-win32* 69 | bzip2_prefix -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | 'use strict'; 3 | 4 | var moment = require('moment'), 5 | path = require('path'), 6 | packager = require('electron-packager'); 7 | 8 | var os = (function(){ 9 | var platform = process.platform; 10 | if (/^win/.test(platform)) { return "windows"; } 11 | if (/^darwin/.test(platform)) { return "mac"; } 12 | if (/^linux/.test(platform)) { return "linux"; } 13 | return null; 14 | })(); 15 | 16 | var exe = { 17 | windows: "electron.exe", 18 | mac: "Electron.app/Contents/MacOS/Electron", 19 | linux: "electron" 20 | }; 21 | 22 | var electron_path = "electron"; 23 | var electron_version = "0.36.9"; 24 | 25 | var packageJson = require(__dirname + '/package.json'); 26 | 27 | //------------------------------------------------------------------------------ 28 | // ShellJS 29 | //------------------------------------------------------------------------------ 30 | 31 | require('shelljs/global'); 32 | // shelljs/global makes the following imports: 33 | // cwd, pwd, ls, find, cp, rm, mv, mkdir, test, cat, 34 | // str.to, str.toEnd, sed, grep, which, echo, 35 | // pushd, popd, dirs, ln, exit, env, exec, chmod, 36 | // tempdir, error 37 | 38 | var shellconfig = require('shelljs').config; 39 | shellconfig.silent = false; // hide shell cmd output? 40 | shellconfig.fatal = false; // stop if cmd failed? 41 | 42 | //------------------------------------------------------------------------------ 43 | // Grunt Config 44 | //------------------------------------------------------------------------------ 45 | 46 | 47 | grunt.initConfig({ 48 | 49 | 'download-electron': { 50 | version: electron_version, 51 | outputDir: 'electron' 52 | } 53 | 54 | }); 55 | 56 | //------------------------------------------------------------------------------ 57 | // Third-party tasks 58 | //------------------------------------------------------------------------------ 59 | 60 | 61 | grunt.loadNpmTasks('grunt-download-electron'); 62 | if (os === "mac") { 63 | grunt.loadNpmTasks('grunt-appdmg'); 64 | } 65 | grunt.loadNpmTasks('winresourcer'); 66 | 67 | //------------------------------------------------------------------------------ 68 | // Setup Tasks 69 | //------------------------------------------------------------------------------ 70 | 71 | grunt.registerTask('setup', [ 72 | 'download-electron', 73 | 'ensure-config-exists', 74 | 'run-app-bower' 75 | ]); 76 | 77 | grunt.registerTask('ensure-config-exists', function() { 78 | pushd("app"); 79 | if (!test("-f", "config.json")) { 80 | grunt.log.writeln("Creating default config.json..."); 81 | cp("example.config.json", "config.json"); 82 | } 83 | popd(); 84 | }); 85 | 86 | grunt.registerTask('run-app-bower', function() { 87 | exec("bower install"); 88 | }); 89 | 90 | grunt.registerTask('cljsbuild-prod', function() { 91 | grunt.log.writeln("\nCleaning and building ClojureScript production files..."); 92 | exec("lein do clean, with-profile production cljsbuild once"); 93 | }); 94 | 95 | grunt.registerTask('launch', function(async) { 96 | var IsAsync = (async == "true"); 97 | grunt.log.writeln("\nLaunching development version..."); 98 | var local_exe = exe[os]; 99 | exec(path.join(electron_path, local_exe) + " app", {async:IsAsync}); 100 | }); 101 | 102 | grunt.registerTask('check-old', function() { 103 | grunt.log.writeln("\nChecking clojure dependencies"); 104 | exec("lein ancient :all", {silent:false}); 105 | grunt.log.writeln("\nChecking npm dependencies"); 106 | exec("npm outdated", {silent:false}); 107 | grunt.log.writeln("\nChecking bower dependencies"); 108 | exec("bower list", {silent:false}); 109 | }); 110 | 111 | //------------------------------------------------------------------------------ 112 | // Test Tasks 113 | //------------------------------------------------------------------------------ 114 | 115 | //------------------------------------------------------------------------------ 116 | // Release Helper functions 117 | //------------------------------------------------------------------------------ 118 | 119 | function setReleaseConfig(build, paths) { 120 | grunt.log.writeln("\nRemoving config to force default release settings..."); 121 | rm('-f', paths.releaseCfg); 122 | cp(paths.prodCfg, paths.releaseCfg); 123 | } 124 | 125 | function getBuildMeta() { 126 | grunt.log.writeln("Getting project metadata..."); 127 | var tokens = cat("project.clj").split(" "); 128 | var build = { 129 | name: tokens[1], 130 | version: tokens[2].replace(/"/g, "").trim(), 131 | date: moment().format("YYYY-MM-DD") 132 | }; 133 | var tag = exec("git tag --points-at HEAD", {silent:true}).output.trim(); 134 | if (tag == 'v' + build.version) { 135 | build.commit = ""; 136 | } else { 137 | build.commit = exec("git rev-list --max-count=1 HEAD", {silent:true}).output.trim(); 138 | } 139 | build.releaseName = build.name + "-v" + build.version + 140 | (build.commit ? "-" + build.commit : ""); 141 | return build; 142 | } 143 | 144 | function getReleasePaths(build) { 145 | var paths = { 146 | builds: "builds", 147 | devApp: "app", 148 | rootPkg: "package.json" 149 | }; 150 | paths.release = path.join(paths.builds, build.releaseName); 151 | paths.devPkg = path.join(paths.devApp, "package.json"); 152 | paths.prodCfg = path.join(paths.devApp, "prod.config.json"); 153 | paths.releaseApp = path.join(paths.builds, paths.devApp); 154 | paths.releasePkg = path.join(paths.releaseApp, "package.json"); 155 | paths.releaseCfg = path.join(paths.releaseApp, "config.json"); 156 | paths.releaseResources = path.join(paths.releaseApp, "components"); 157 | return paths; 158 | } 159 | 160 | function getBasicReleaseInfo(build, paths, platform) { 161 | var opts = { 162 | "dir": paths.releaseApp, 163 | "name": packageJson.name, 164 | "version": electron_version, 165 | "asar": true, 166 | "out": paths.release, 167 | "overwrite": true, 168 | "app-bundle-id": "org.zestdocs", 169 | "app-version": build.version, 170 | "version-string": { 171 | "ProductVersion": build.version, 172 | "ProductName": packageJson.name, 173 | } 174 | }; 175 | if (platform == 'darwin' || platform == 'mas') { 176 | opts.name = opts.name.charAt(0).toUpperCase() + opts.name.slice(1); 177 | } 178 | return opts; 179 | } 180 | 181 | function stampRelease(build, paths) { 182 | grunt.log.writeln("\nStamping release with build metadata..."); 183 | var pkg = grunt.file.readJSON(paths.releasePkg); 184 | pkg.version = build.version; 185 | pkg["build-commit"] = build.commit; 186 | pkg["build-date"] = build.date; 187 | JSON.stringify(pkg, null, " ").to(paths.releasePkg); 188 | } 189 | 190 | function defineRelease(done, extra_opts, cb) { 191 | var callback = cb || (function () {}); 192 | var build = getBuildMeta(); 193 | var paths = getReleasePaths(build); 194 | var basic_opts = getBasicReleaseInfo(build, paths, extra_opts.platform); 195 | var opts = Object.assign(basic_opts, extra_opts); 196 | 197 | packager(opts, function(err, appPath) { 198 | if (err) { 199 | grunt.log.writeln("Error: ".red, err); 200 | } 201 | if (appPath) { 202 | if (Array.isArray(appPath)) { 203 | appPath.forEach(function(i) { 204 | callback(i); 205 | grunt.log.writeln("Build: " + i.cyan); 206 | }); 207 | } else { 208 | callback(appPath); 209 | grunt.log.writeln("Build: " + appPath.cyan); 210 | } 211 | } 212 | done(err); 213 | }); 214 | } 215 | 216 | function deleteExtraResources(paths) { 217 | rm('-rf', path.join(paths.releaseApp, "js", "p", "out")); 218 | } 219 | 220 | 221 | //------------------------------------------------------------------------------ 222 | // Tasks 223 | //------------------------------------------------------------------------------ 224 | 225 | grunt.registerTask('release', ['cljsbuild-prod', 'prepare-release', 'release-linux']); 226 | 227 | grunt.registerTask('cljsbuild-prod', function() { 228 | grunt.log.writeln("\nCleaning and building ClojureScript production files..."); 229 | exec("lein do clean, with-profile production cljsbuild once"); 230 | }); 231 | 232 | grunt.registerTask('prepare-release', function() { 233 | var build = getBuildMeta(); 234 | var paths = getReleasePaths(build); 235 | 236 | grunt.log.writeln("name: "+build.name.cyan); 237 | grunt.log.writeln("version: "+build.version.cyan); 238 | grunt.log.writeln("date: "+build.date.cyan); 239 | grunt.log.writeln("commit: "+build.commit.cyan); 240 | grunt.log.writeln("release: "+build.releaseName.cyan); 241 | 242 | mkdir('-p', paths.builds); 243 | 244 | if (test("-d", paths.releaseApp)) { 245 | rm('-r', paths.releaseApp); 246 | } 247 | 248 | if (test("-d", paths.release)) { 249 | rm('-rf', paths.release); 250 | } 251 | 252 | //copy app folder 253 | cp('-r', paths.devApp, paths.builds); 254 | 255 | grunt.log.writeln("\nCopying node dependencies to release..."); 256 | cp('-f', paths.rootPkg, paths.releaseApp); 257 | pushd(paths.releaseApp); 258 | exec('npm install --no-optional --production --silent'); 259 | popd(); 260 | cp('-f', paths.devPkg, paths.releaseApp); 261 | 262 | deleteExtraResources(paths); 263 | stampRelease(build, paths); 264 | setReleaseConfig(build, paths); 265 | }); 266 | 267 | grunt.registerTask('release-linux', function() { 268 | var done = this.async(); 269 | var opts = { 270 | "arch": ["x64"], 271 | "platform": "linux" 272 | } 273 | defineRelease(done, opts); 274 | }); 275 | 276 | grunt.registerTask('makensis', function() { 277 | grunt.log.writeln("\nCreating installer..."); 278 | var config = grunt.config.get("makensis"); 279 | 280 | var ret = exec(["makensis", 281 | "-DPRODUCT_VERSION=" + config.version, 282 | "-DRELEASE_DIR=" + config.releaseDir, 283 | "-DOUTFILE=" + config.outFile, 284 | "scripts/build-windows-exe.nsi"].join(" ")); 285 | 286 | if(ret.code === 0) { 287 | // grunt.log.writeln("\nInstaller created. Removing win32 folder:", config.releaseDir.cyan); 288 | // rm('-rf', config.releaseDir); 289 | } 290 | }); 291 | 292 | 293 | grunt.registerTask('release-win', function() { 294 | var done = this.async(); 295 | var build = getBuildMeta(); 296 | var cb = function (appPath) { 297 | if (which("makensis")) { 298 | var dirName = path.join(appPath, ".."); 299 | var exeName = path.join(dirName, path.basename(dirName) + ".exe"); 300 | grunt.config.set("makensis", { 301 | version: build.version, 302 | releaseDir: path.resolve(appPath), // absolute paths required on linux 303 | outFile: path.resolve(exeName) 304 | }); 305 | grunt.task.run("makensis"); 306 | } 307 | else { 308 | grunt.log.writeln("\nSkipping windows installer creation:", "makensis not installed or not in path".cyan); 309 | } 310 | }; 311 | cb('builds/'+build.releaseName+'/zest-win32-x64'); 312 | done(); 313 | }); 314 | grunt.registerTask('prepare-win', function() { 315 | var done = this.async(); 316 | var opts = { 317 | "arch": ["x64"], 318 | "platform": "win32", 319 | "icon": "app/img/logo.ico" 320 | } 321 | defineRelease(done, opts, function() { }); 322 | }); 323 | 324 | grunt.registerTask('release-mac', function() { 325 | var done = this.async(); 326 | var cb = null; 327 | if (os === "mac") { 328 | cb = function (f) { 329 | var dirName = path.join(f, "..") 330 | var dmgName = path.join(dirName, path.basename(dirName) + ".dmg"); 331 | grunt.config.set("appdmg", { 332 | options: { 333 | "title": "zest", 334 | "background": "scripts/dmg/TestBkg.png", 335 | "icon-size": 80, 336 | "contents": [ 337 | { "x": 448, "y": 344, "type": "link", "path": "/Applications" }, 338 | { "x": 192, "y": 344, "type": "file", "path": path.join(f, packageJson.name + ".app") } 339 | ] 340 | }, 341 | target: { 342 | dest: dmgName 343 | } 344 | }); 345 | grunt.task.run("appdmg"); 346 | } 347 | } 348 | var opts = { 349 | "arch": "x64", 350 | "platform": "darwin", 351 | "icon": "app/img/logo.icns" 352 | } 353 | defineRelease(done, opts, cb); 354 | }); 355 | 356 | 357 | //------------------------------------------------------------------------------ 358 | // Default Task 359 | //------------------------------------------------------------------------------ 360 | 361 | grunt.registerTask('default', ['setup']); 362 | 363 | // end module.exports 364 | }; 365 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Jerzy Kozera 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /LucenePlusPlusCMakeLists.txt.appveyor: -------------------------------------------------------------------------------- 1 | project(lucene++) 2 | 3 | cmake_minimum_required(VERSION 2.8.6) 4 | 5 | set(lucene++_VERSION_MAJOR 3) 6 | set(lucene++_VERSION_MINOR 0) 7 | set(lucene++_VERSION_PATCH 7) 8 | 9 | set(lucene++_SOVERSION "0") 10 | 11 | set(lucene++_VERSION 12 | "${lucene++_VERSION_MAJOR}.${lucene++_VERSION_MINOR}.${lucene++_VERSION_PATCH}" 13 | ) 14 | 15 | # include specific modules 16 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") 17 | 18 | #################################### 19 | # pre-compiled headers support 20 | #################################### 21 | include(cotire) 22 | 23 | # if setup using the Toolchain-llvm.cmake file, then use llvm... 24 | if(ENABLE_LLVM) 25 | include(Toolchain-llvm) 26 | endif() 27 | 28 | #################################### 29 | # user specified build options 30 | #################################### 31 | if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) 32 | set(CMAKE_BUILD_TYPE "Release") 33 | endif() 34 | 35 | option(ENABLE_PACKAGING 36 | "Create build scripts for creating lucene++ packages" 37 | OFF 38 | ) 39 | option(LUCENE_USE_STATIC_BOOST_LIBS 40 | "Use static boost libraries" 41 | OFF 42 | ) 43 | option(ENABLE_BOOST_INTEGER 44 | "Enable boost integer types" 45 | OFF 46 | ) 47 | option(ENABLE_CYCLIC_CHECK 48 | "Enable cyclic checking" 49 | OFF 50 | ) 51 | option(ENABLE_TEST 52 | "Enable the tests" 53 | ON 54 | ) 55 | option(ENABLE_DEMO 56 | "Enable building demo applications" 57 | ON 58 | ) 59 | 60 | #################################### 61 | # bootstrap 62 | #################################### 63 | 64 | find_package(Threads REQUIRED) 65 | find_package(Boost COMPONENTS 66 | date_time 67 | filesystem 68 | regex 69 | system 70 | thread 71 | REQUIRED 72 | ) 73 | 74 | set(Boost_USE_MULTITHREADED ON) 75 | set(Boost_USE_STATIC_LIBS ${LUCENE_USE_STATIC_BOOST_LIBS}) 76 | 77 | set(lucene_boost_libs 78 | ${Boost_LIBRARIES} 79 | ${Boost_FILESYSTEM_LIBRARIES} 80 | "C:\\Libraries\\boost_1_59_0\\stage\\lib\\libboost_iostreams-vc120-mt-1_59.lib" 81 | ${Boost_REGEX_LIBRARIES} 82 | ${Boost_SYSTEM_LIBRARIES} 83 | ${Boost_THREAD_LIBRARIES} 84 | "C:\\Libraries\\boost_1_59_0\\stage\\lib\\libboost_zlib-vc120-mt-1_59.lib" 85 | ) 86 | 87 | include(Lucene++Docs) 88 | include(TestCXXAcceptsFlag) 89 | include(GNUInstallDirs) 90 | 91 | set(LIB_DESTINATION 92 | "${CMAKE_INSTALL_FULL_LIBDIR}" CACHE STRING "Define lib output directory name" 93 | ) 94 | 95 | if(ENABLE_BOOST_INTEGER) 96 | set(DEFINE_USE_BOOST_INTEGER "define") 97 | else() 98 | set(DEFINE_USE_BOOST_INTEGER "undef") 99 | endif() 100 | 101 | if(ENABLE_CYCLIC_CHECK) 102 | set(DEFINE_USE_CYCLIC_CHECK "define") 103 | else() 104 | set(DEFINE_USE_CYCLIC_CHECK "undef") 105 | endif() 106 | 107 | #################################### 108 | # platform specific options 109 | #################################### 110 | if(WIN32 OR WIN64) 111 | set(CMAKE_DEBUG_POSTFIX "d") 112 | endif() 113 | 114 | if(MSVC) 115 | # Disable automatic boost linking on Windows as libraries are added to the linker explicitly 116 | add_definitions(-DBOOST_ALL_NO_LIB) 117 | 118 | # enable exceptions, see http://msdn.microsoft.com/en-us/library/1deeycx5.aspx 119 | add_definitions(-EHsc) 120 | endif() 121 | 122 | if(NOT WIN32 AND NOT CMAKE_SYSTEM MATCHES "SunOS-5*.") 123 | add_definitions(-fPIC) 124 | endif() 125 | 126 | if(CYGWIN) 127 | add_definitions(-D__LARGE64_FILES) 128 | endif() 129 | 130 | if(APPLE) 131 | set(CMAKE_MACOSX_RPATH ON) 132 | set(CMAKE_SKIP_BUILD_RPATH FALSE) 133 | set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) 134 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 135 | set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) 136 | list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) 137 | if("${isSystemDir}" STREQUAL "-1") 138 | set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") 139 | endif() 140 | endif() 141 | 142 | ################################# 143 | # generate Config.h 144 | ################################# 145 | configure_file( 146 | "${CMAKE_CURRENT_SOURCE_DIR}/include/Config.h.cmake" 147 | "${CMAKE_CURRENT_BINARY_DIR}/include/Config.h" @ONLY 148 | ) 149 | 150 | include_directories( 151 | "${CMAKE_CURRENT_BINARY_DIR}/include" 152 | ) 153 | 154 | 155 | add_subdirectory(src/core) 156 | add_subdirectory(src/contrib) 157 | 158 | if(ENABLE_DEMO) 159 | add_subdirectory(src/demo) 160 | endif() 161 | 162 | if(ENABLE_TEST) 163 | enable_testing() 164 | add_subdirectory(src/test) 165 | endif() 166 | 167 | ################################# 168 | # install pkg-config file 169 | ################################# 170 | if(NOT WIN32) 171 | configure_file( 172 | "${CMAKE_CURRENT_SOURCE_DIR}/liblucene++.pc.cmake" 173 | "${CMAKE_CURRENT_BINARY_DIR}/liblucene++.pc" @ONLY) 174 | configure_file( 175 | "${CMAKE_CURRENT_SOURCE_DIR}/liblucene++-contrib.pc.cmake" 176 | "${CMAKE_CURRENT_BINARY_DIR}/liblucene++-contrib.pc" @ONLY) 177 | install( 178 | FILES 179 | "${CMAKE_CURRENT_BINARY_DIR}/liblucene++.pc" 180 | "${CMAKE_CURRENT_BINARY_DIR}/liblucene++-contrib.pc" 181 | DESTINATION "${LIB_DESTINATION}/pkgconfig") 182 | endif() 183 | 184 | ################################# 185 | # install Config.h 186 | ################################# 187 | install( 188 | FILES 189 | "${CMAKE_CURRENT_BINARY_DIR}/include/Config.h" 190 | DESTINATION include/lucene++) 191 | 192 | #################################### 193 | # custom targets 194 | #################################### 195 | configure_file( 196 | "${CMAKE_MODULE_PATH}/cmake_uninstall.cmake.in" 197 | "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 198 | IMMEDIATE @ONLY 199 | ) 200 | 201 | add_custom_target( 202 | uninstall 203 | "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" 204 | VERBATIM 205 | ) 206 | 207 | if(ENABLE_PACKAGING) 208 | include(CreateLucene++Packages) 209 | endif() 210 | 211 | message("** Build Summary **") 212 | message(" Version: ${lucene++_VERSION}") 213 | message(" Prefix: ${CMAKE_INSTALL_PREFIX}") 214 | message(" Build Type: ${CMAKE_BUILD_TYPE}") 215 | message(" Architecture: ${CMAKE_SYSTEM_PROCESSOR}") 216 | message(" System: ${CMAKE_SYSTEM_NAME}") 217 | message(" Boost Include: ${Boost_INCLUDE_DIRS}") 218 | message(" Boost Library: ${Boost_LIBRARY_DIRS}") 219 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Project status 2 | 3 | As mentioned at https://zestdocs.github.io/ I've now decided to stop maintaining Zest. Hence please do not expect updates or support. If anyone is insterested in continuing, feel free to contact me at the email from the commit messages. I'd be willing to transfer the zestdocs.org domain and Mac App Store app ownership in case someone shows more interest than me. 4 | 5 | It [was certainly fun](https://medium.com/@jerzy.kozera/from-zeal-devdocs-to-zest-my-docs-journey-93fa4bf08a8f#.t59nt74b7) to implement this project, but sadly I don't have enough motivation to continue at this point. I feel obliged to let the users know about this decision, hence the notice. 6 | 7 | # zest 8 | 9 | Early Proof of Concept prototype. It's my first ClojureScript project ever, etc. Not really meant for release, published mostly in case someone wants to collaborate. 10 | 11 | ## Requirements 12 | 13 | * JDK 1.7+ 14 | * Leiningen 2.5.3 15 | * Recent node.js 16 | * Lucene++ (available at https://github.com/luceneplusplus/LucenePlusPlus) 17 | * libarchive 18 | * [NSIS](http://nsis.sourceforge.net/) 19 | 20 | On Mac/Linux, installing node.js using [Node Version Manager](https://github.com/creationix/nvm) is recommended. 21 | 22 | This project uses Electron v0.35.2. Please check [Electron's GitHub page](https://github.com/atom/electron) for the latest version. The version is specified in `Gruntfile.js` under the `Grunt Config` section. 23 | 24 | ## Setup 25 | 26 | On Mac/Linux: 27 | 28 | ``` 29 | scripts/setup.sh 30 | ``` 31 | 32 | On Windows: 33 | 34 | ``` 35 | scripts\setup.bat 36 | ``` 37 | 38 | This will install the node dependencies for the project, along with grunt and bower and will also run `grunt setup`. 39 | 40 | 41 | ## Development mode 42 | 43 | Start the figwheel server: 44 | 45 | ``` 46 | lein figwheel 47 | ``` 48 | 49 | If you are on OSX/Linux and have `rlwrap` installed, you can start the figwheel server with: 50 | 51 | ``` 52 | rlwrap lein figwheel 53 | ``` 54 | 55 | This will give better readline support. 56 | 57 | More about [figwheel](https://github.com/bhauman/lein-figwheel) here. 58 | 59 | 60 | In another terminal window, launch the electron app: 61 | 62 | ``` 63 | grunt launch 64 | ``` 65 | 66 | You can edit the `src/cljs/zest/core.cljs` file and the changes should show up in the electron app without the need to re-launch. 67 | 68 | ## Using nREPL with figwheel 69 | 70 | - Start the repl using `lein repl`. 71 | 72 | ``` 73 | user> (use 'figwheel-sidecar.repl-api) 74 | nil 75 | user> (def figwheel-config 76 | {:figwheel-options {:css-dirs ["app/css"]} 77 | :build-ids ["dev"] 78 | :all-builds 79 | [{:id "dev" 80 | :figwheel {:on-jsload "zest.core/on-figwheel-reload"} 81 | :source-paths ["src/cljs" "env/dev/cljs"] 82 | :compiler {:main "zest.dev" 83 | :asset-path "js/p/out" 84 | :output-to "app/js/p/app.js" 85 | :output-dir "app/js/p/out" }}]}) 86 | #'user/figwheel-config 87 | user> (start-figwheel! figwheel-config) 88 | Figwheel: Starting server at http://localhost:3449 89 | Figwheel: Watching build - dev 90 | Compiling "resources/public/js/repler.js" from ["src/cljs" "env/dev/cljs"]... 91 | Successfully compiled "app/js/p/app.js" in 2.06 seconds. 92 | Figwheel: Starting CSS Watcher for paths ["app/css"] 93 | # 94 | ``` 95 | 96 | See [Figwheel wiki](https://github.com/bhauman/lein-figwheel/wiki/Using-the-Figwheel-REPL-within-NRepl) for more details. 97 | 98 | ## Dependencies 99 | 100 | Node dependencies are in `package.json` file. Bower dependencies are in `bower.json` file. Clojure/ClojureScript dependencies are in `project.clj`. 101 | 102 | ## Icons 103 | 104 | Please replace the icons provided with your application's icons. The development icons are from [node-appdmg](https://github.com/LinusU/node-appdmg) project. 105 | 106 | Files to replace: 107 | 108 | * app/img/logo.icns 109 | * app/img/logo.ico 110 | * app/img/logo_96x96.png 111 | * scripts/dmg/TestBkg.png 112 | * scripts/dmg/TestBkg@2x.png 113 | 114 | ## Creating a build for release 115 | 116 | To create a Windows build from a non-Windows platform, please install `wine`. On OS X, an easy option is using homebrew. 117 | 118 | On Windows before doing a production build, please edit the `scripts/build-windows-exe.nsi` file. The file is the script for creating the NSIS based setup file. 119 | 120 | On Mac OSX, please edit the variables for the plist in `release-mac` task in `Gruntfile.js`. 121 | 122 | Using [`electron-packager`](https://github.com/maxogden/electron-packager), we are able to create a directory which has OS executables (.app, .exe etc) running from any platform. 123 | 124 | If NSIS is available on the path, a further setup executable will be created for Windows. Further, if the release command is run from a OS X machine, a DMG file will be created. 125 | 126 | To create the release directories: 127 | 128 | ``` 129 | grunt release 130 | ``` 131 | 132 | This will create the directories in the `builds` folder. 133 | 134 | Note: you will need to be on OSX to create a DMG file and on Windows to create the setup .exe file. 135 | 136 | 137 | ## Grunt commands 138 | 139 | To run a command, type `grunt ` in the terminal. 140 | 141 | 142 | | Command | Description | 143 | |---------------|-------------------------------------------------------------------------------------------| 144 | | setup | Download electron project, installs bower dependencies and setups up the app config file. | 145 | | launch | Launches the electron app | 146 | | release | Creates a Win/OSX/Linux executables | 147 | | outdated | List all outdated clj/cljs/node/bower dependencies | 148 | 149 | ## Leiningen commands 150 | 151 | To run a command, type `lein ` in the terminal. 152 | 153 | | Command | Description | 154 | |---------------|-------------------------------------------------------------------------------------------| 155 | | cljfmt fix | Auto-formats all clj/cljs code. See [cljfmt](https://github.com/weavejester/cljfmt) | 156 | | kibit | Statically analyse clj/cljs and give suggestions | 157 | 158 | 159 | ## Acknowledgements 160 | 161 | - Electron project template - https://github.com/ducky427/electron-template 162 | 163 | ``` 164 | The MIT License (MIT) 165 | 166 | Copyright (c) 2015 Rohit Aggarwal 167 | 168 | Permission is hereby granted, free of charge, to any person obtaining a copy 169 | of this software and associated documentation files (the "Software"), to deal 170 | in the Software without restriction, including without limitation the rights 171 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 172 | copies of the Software, and to permit persons to whom the Software is 173 | furnished to do so, subject to the following conditions: 174 | 175 | The above copyright notice and this permission notice shall be included in all 176 | copies or substantial portions of the Software. 177 | 178 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 179 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 180 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 181 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 182 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 183 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 184 | SOFTWARE. 185 | ``` 186 | 187 | - https://news.ycombinator.com/item?id=10844862 for inspiring me to implement 188 | the same project again :) 189 | 190 | # Basic Proof of Concept usage 191 | 192 | DevDocs downloader, Stack Overflow torrent downloader, and Stack Overflow indexer are now implemented in the "Settings" modal. 193 | 194 | `extractor`, `sogrep`, and `searcher` binaries need to be in the root directory of this repo. (`extractor`+`sogrep` and `searcher` can be built from the `sogrep-src/` and `nodelucene/` directories respectively - `cmake . && make` should do it, given installed libarchive, xerces, leveldb, rapidjson, and Lucene++) 195 | -------------------------------------------------------------------------------- /app/app.js: -------------------------------------------------------------------------------- 1 | var electron = require('electron'), 2 | fs = require('fs-extra'), 3 | path = require('path'), 4 | shell = require('shell'), 5 | packageJson = require(__dirname + '/package.json'); 6 | 7 | var ipc = electron.ipcMain; 8 | var app = electron.app; 9 | var dialog = electron.dialog; 10 | var BrowserWindow = electron.BrowserWindow; 11 | var Menu = electron.Menu; 12 | 13 | // Report crashes to atom-shell. 14 | require('crash-reporter').start(); 15 | 16 | const devConfigFile = __dirname + '/config.json'; 17 | var devConfig = {}; 18 | if (fs.existsSync(devConfigFile)) { 19 | devConfig = require(devConfigFile); 20 | } 21 | 22 | 23 | const isDev = (packageJson.version.indexOf("DEV") !== -1); 24 | const onMac = (process.platform === 'darwin'); 25 | const acceleratorKey = onMac ? "Command" : "Control"; 26 | const isInternal = (devConfig.hasOwnProperty('internal') && devConfig['internal'] === true); 27 | 28 | 29 | 30 | // Keep a global reference of the window object, if you don't, the window will 31 | // be closed automatically when the javascript object is GCed. 32 | var mainWindow = null; 33 | 34 | // make sure app.getDataPath() exists 35 | // https://github.com/oakmac/cuttle/issues/92 36 | fs.ensureDirSync(app.getPath('userData')); 37 | 38 | 39 | //------------------------------------------------------------------------------ 40 | // Main 41 | //------------------------------------------------------------------------------ 42 | 43 | const versionString = "Version " + packageJson.version + "\nDate " + packageJson["build-date"] + "\nCommit " + packageJson["build-commit"]; 44 | 45 | 46 | function showVersion() { 47 | dialog.showMessageBox({type: "info", title: "Version", buttons: ["OK"], message: versionString}); 48 | } 49 | 50 | var fileMenu = { 51 | label: 'File', 52 | submenu: [ 53 | { 54 | label: 'Settings...', 55 | accelerator: acceleratorKey + '+,', 56 | click: function () { 57 | mainWindow.webContents.executeJavaScript('window.showSettings()'); 58 | } 59 | }, 60 | { type: 'separator' }, 61 | { 62 | label: 'Quit', 63 | accelerator: acceleratorKey + '+Q', 64 | click: function () 65 | { 66 | app.quit(); 67 | } 68 | }] 69 | }; 70 | 71 | var editMenu = { 72 | label: "Edit", 73 | submenu: [ 74 | { label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" }, 75 | { label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" }, 76 | { type: "separator" }, 77 | { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" }, 78 | { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" }, 79 | { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" }, 80 | { label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }, 81 | { type: "separator" }, 82 | { label: "Find", accelerator: "CmdOrCtrl+F", selector: "find:" , 83 | click: function () { 84 | mainWindow.webContents.executeJavaScript('window.showFind()'); 85 | } 86 | } 87 | ] 88 | }; 89 | 90 | 91 | var helpMenu = { 92 | label: 'Help', 93 | submenu: [ 94 | { 95 | label: 'Version', 96 | click: showVersion 97 | }] 98 | }; 99 | 100 | var debugMenu = { 101 | label: 'Debug', 102 | submenu: [ 103 | { 104 | label: 'Toggle DevTools', 105 | click: function () 106 | { 107 | mainWindow.toggleDevTools(); 108 | } 109 | } 110 | ] 111 | }; 112 | 113 | var menuTemplate = [fileMenu, editMenu, debugMenu, helpMenu]; 114 | 115 | 116 | // NOTE: not all of the browserWindow options listed on the docs page work 117 | // on all operating systems 118 | const browserWindowOptions = { 119 | height: 850, 120 | title: 'zest', 121 | width: 1400, 122 | icon: __dirname + '/img/logo_96x96.png' 123 | }; 124 | 125 | 126 | //------------------------------------------------------------------------------ 127 | // Register IPC Calls from the Renderers 128 | //------------------------------------------------------------------------------ 129 | 130 | 131 | //------------------------------------------------------------------------------ 132 | // Ready 133 | //------------------------------------------------------------------------------ 134 | 135 | app.processCmdLine = function(commandLine) { 136 | if (commandLine.length > 2 && 137 | commandLine[commandLine.length - 2] == '--query') { 138 | var query = commandLine[commandLine.length - 1]; 139 | var docsets = query.split(':', 2)[0]; 140 | query = query.split(':', 2)[1]; 141 | mainWindow.webContents.executeJavaScript('setQuery(' + 142 | JSON.stringify(query) + ', ' + 143 | JSON.stringify(docsets) + 144 | ')'); 145 | } else if (commandLine[commandLine.length - 1].indexOf('dash-plugin://') == 0) { 146 | var url = commandLine[commandLine.length - 1]; 147 | if (url.indexOf('?') != url.indexOf('//') + 2) { 148 | // fix for missing question mark from some plugins 149 | url = url.replace('//', '//?'); 150 | } 151 | var parsed = require('url').parse(url, true); 152 | mainWindow.webContents.executeJavaScript('setQuery(' + 153 | JSON.stringify(parsed.query.query) + ', ' + 154 | (parsed.query.keys ? JSON.stringify(parsed.query.keys) : 'null') + 155 | ')'); 156 | } 157 | } 158 | 159 | var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { 160 | // Someone tried to run a second instance, we should focus our window. 161 | 162 | app.processCmdLine(commandLine); 163 | 164 | if (mainWindow) { 165 | if (mainWindow.isMinimized()) mainWindow.restore(); 166 | mainWindow.focus(); 167 | } 168 | return true; 169 | }); 170 | 171 | if (shouldQuit) { 172 | app.quit(); 173 | return; 174 | } 175 | 176 | 177 | // This method will be called when atom-shell has done everything 178 | // initialization and ready for creating browser windows. 179 | app.on('ready', function() { 180 | // Create the browser window. 181 | mainWindow = new BrowserWindow(browserWindowOptions); 182 | 183 | // and load the index.html of the app. 184 | mainWindow.loadURL('file://' + __dirname + '/index.html'); 185 | 186 | var menu = Menu.buildFromTemplate(menuTemplate); 187 | 188 | Menu.setApplicationMenu(menu); 189 | 190 | // Emitted when the window is closed. 191 | mainWindow.on('closed', function() { 192 | // Dereference the window object, usually you would store windows 193 | // in an array if your app supports multi windows, this is the time 194 | // when you should delete the corresponding element. 195 | mainWindow = null; 196 | app.quit(); 197 | }); 198 | 199 | if (devConfig.hasOwnProperty('dev-tools') && devConfig['dev-tools'] === true) { 200 | mainWindow.openDevTools(); 201 | } 202 | 203 | }); 204 | -------------------------------------------------------------------------------- /app/css/2fcrYFNaTjcS6g4U3t-Y5UEw0lE80llgEseQY3FEmqw.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/css/2fcrYFNaTjcS6g4U3t-Y5UEw0lE80llgEseQY3FEmqw.woff2 -------------------------------------------------------------------------------- /app/css/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/css/icons.png -------------------------------------------------------------------------------- /app/css/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/css/icons@2x.png -------------------------------------------------------------------------------- /app/css/main.css: -------------------------------------------------------------------------------- 1 | th { 2 | color: black; /* fixes angular doc */ 3 | } 4 | 5 | a:hover { 6 | box-shadow: none; 7 | } 8 | 9 | #settings-modal { 10 | min-width: 1000px; 11 | max-height: 90%; 12 | top: 5% !important; 13 | } 14 | 15 | @font-face { 16 | font-family: 'Material Icons'; 17 | font-style: normal; 18 | font-weight: 400; 19 | src: url(2fcrYFNaTjcS6g4U3t-Y5UEw0lE80llgEseQY3FEmqw.woff2) format('woff2'); 20 | } 21 | 22 | .material-icons { 23 | font-family: 'Material Icons'; 24 | font-weight: normal; 25 | font-style: normal; 26 | font-size: 24px; 27 | line-height: 1; 28 | letter-spacing: normal; 29 | text-transform: none; 30 | display: inline-block; 31 | white-space: nowrap; 32 | word-wrap: normal; 33 | direction: ltr; 34 | -webkit-font-feature-settings: 'liga'; 35 | -webkit-font-smoothing: antialiased; 36 | } 37 | 38 | .searchDocset { 39 | display: flex; 40 | height: 3rem; 41 | position: absolute; 42 | width: inherit; 43 | align-items: flex-end; 44 | justify-content: flex-end; 45 | color: #aaa; 46 | padding: 0.5rem; 47 | font-size: 75%; 48 | z-index: -1000; 49 | } 50 | #searchInput { 51 | padding: 0; 52 | margin: 0; 53 | padding: 0 0.5rem; 54 | box-sizing: border-box; 55 | } 56 | 57 | #left { 58 | line-height: 1.5; 59 | font-family: "Roboto", sans-serif; 60 | font-weight: normal; 61 | color: rgba(0, 0, 0, 0.87); 62 | } 63 | 64 | /* split.js */ 65 | .split, .gutter.gutter-horizontal, #left, #right { 66 | height: 100%; 67 | float: left; 68 | } 69 | #right-contents { 70 | height: 100%; 71 | } 72 | 73 | .tree { 74 | box-shadow: none; 75 | position: absolute; 76 | top: 3rem; 77 | margin: 1px 0; 78 | bottom: 0; 79 | overflow-y: auto; 80 | overflow-x: hidden; 81 | width: inherit; 82 | } 83 | 84 | .tree .level2 { 85 | box-shadow: none; 86 | margin: 0; 87 | margin-top: -1px; 88 | margin-left: 1rem; 89 | } 90 | 91 | 92 | #right .pageSearchInput { 93 | height: 3rem; 94 | padding-bottom: 2px; 95 | padding-left: 1rem; 96 | box-sizing: content-box; 97 | position: fixed; 98 | right:0; 99 | z-index: 10000; 100 | } 101 | #right .pageSearchInput a { 102 | width: 36px; 103 | padding: 0; 104 | } 105 | #right .pageSearchInput input { 106 | margin: 0 1rem; 107 | width: 200px; 108 | } 109 | #right .pageSearchInput * { 110 | display: inline-block; 111 | width: auto; 112 | } 113 | .error { 114 | color: red; 115 | } 116 | 117 | .gutter { 118 | background-color: #eee; 119 | 120 | background-repeat: no-repeat; 121 | background-position: 50%; 122 | } 123 | 124 | .gutter.gutter-horizontal { 125 | background-image: url('grips/vertical.png'); 126 | cursor: ew-resize; 127 | } 128 | 129 | 130 | /* https://bitbucket.org/samuel.lai/stackdump/src/15159ac5b5469ddaebf76dc23d1c22dacfb845b5/python/media/css/main.css?at=default&fileviewer=file-view-default */ 131 | 132 | .post-logo { 133 | float: left; 134 | width: 48px; 135 | } 136 | 137 | .post-stats-vertical { 138 | float: left; 139 | width: 64px; 140 | } 141 | 142 | .post-stat { 143 | text-align: center; 144 | background-color: #F2F2F2; 145 | margin-bottom: 5px; 146 | padding: 10px 5px; 147 | } 148 | 149 | .post-stat-img { 150 | background-color: transparent; 151 | } 152 | 153 | .post-stat p { 154 | margin-bottom: 0; 155 | } 156 | 157 | .post-stat-value { 158 | font-weight: bold; 159 | font-size: 16pt; 160 | color: #000000; 161 | } 162 | 163 | .post-stat-value-poor { 164 | color: #AAAAAA; 165 | } 166 | 167 | .post-stat-value-good { 168 | color: #5ebb00; 169 | } 170 | 171 | .post-summary { 172 | padding-left: 72px; /* 64px for post-stats-vertical + 8px for padding */ 173 | } 174 | 175 | .post-summary-with-logo { 176 | padding-left: 120px; /* 48px for post-logo + 64px for post-stats-vertical + 8px for padding */ 177 | } 178 | 179 | .post-summary h3 { 180 | line-height: normal; 181 | padding: 7px 0; 182 | margin-bottom: 0; 183 | } 184 | 185 | .post-details { 186 | float: right; 187 | } 188 | 189 | .post-tags, .post-actions { 190 | margin-bottom: 10px; 191 | } 192 | 193 | .post-actions a { 194 | color: #999999; 195 | } 196 | 197 | .question h1 { 198 | border-bottom: 1px solid #CCCCCC; 199 | padding-bottom: 7px; 200 | margin-top: 15px; 201 | } 202 | 203 | .post-body, .post-metadata, .post-comments { 204 | margin-left: 72px; /* 64px for post-stats-vertical + 8px for padding */ 205 | } 206 | 207 | /* undo the zero margin-bottom imposed by bootstrap */ 208 | .post-body ul, .post-body ol { 209 | margin-bottom: 7px; 210 | } 211 | 212 | .post-body .external-link, .post-comments .external-link { 213 | color: #999999; 214 | } 215 | 216 | .post-metadata { 217 | margin-top: 10px; 218 | padding-top: 10px; 219 | border-top: 1px solid #CCCCCC; 220 | } 221 | 222 | .post-user { 223 | float: right; 224 | margin-left: 50px; 225 | color: #404040; 226 | } 227 | 228 | .post-comments { 229 | clear: right; 230 | } 231 | 232 | .post-comments ul { 233 | list-style: none; 234 | margin-left: 0; 235 | margin-bottom: 18px; 236 | } 237 | 238 | .post-comments li { 239 | border-bottom: 1px solid #E3E3E3; 240 | padding: 7px 4px 7px 0; 241 | color: #404040; 242 | } 243 | 244 | .post-comments li:last-child { 245 | border-bottom: none; 246 | } 247 | 248 | li .post-comment-score { 249 | float: left; 250 | font-weight: bold; 251 | color: #000000; 252 | width: 40px; 253 | text-align: center; 254 | line-height: normal; 255 | margin-bottom: 0; 256 | } 257 | 258 | li .post-comment-text { 259 | margin-left: 40px; 260 | line-height: 20px; 261 | margin-bottom: 0; 262 | } 263 | 264 | /* this rule is needed as comments are wrapped in

...

but we want the 265 | * user name afterwards to appear on the same line. */ 266 | li .post-comment-text > p { 267 | display: inline; 268 | } 269 | 270 | li .post-comment-metadata { 271 | color: #999999; 272 | } 273 | 274 | .show-comments { 275 | display: none; 276 | margin-bottom: 18px; 277 | } 278 | 279 | .user-card { 280 | background-color: #F2F2F2; 281 | } 282 | 283 | .user-card .user-name { 284 | padding: 4px 7px; 285 | } 286 | 287 | .user-card .user-rep { 288 | float: right; 289 | font-weight: bold; 290 | font-size: 15px; 291 | background-color: #CCCCCC; 292 | padding: 4px 7px; 293 | } 294 | 295 | div.moderated { 296 | background-color: #F2F2F2; 297 | padding: 10px; 298 | text-align: center; 299 | margin-left: 0; 300 | } 301 | 302 | div.moderated p { 303 | margin: 0; 304 | font-size: 1.2em; 305 | } 306 | 307 | div.answers { 308 | margin-top: 30px; 309 | } 310 | 311 | ul.answers { 312 | list-style: none; 313 | margin-left: 0; 314 | } 315 | 316 | ul.answers > li { 317 | padding-bottom: 30px; 318 | border-bottom: 1px solid #999999; 319 | margin-top: 30px; 320 | color: #404040; 321 | clear: both; 322 | display: block; 323 | } 324 | 325 | ul.answers > li:last-child { 326 | border-bottom: none; 327 | } 328 | 329 | h1.answers { 330 | margin-bottom: 7px; 331 | line-height: normal; 332 | border-bottom: 1px solid #999999; 333 | padding-bottom: 7px; 334 | } 335 | 336 | .no-answers { 337 | font-size: 24pt; 338 | color: #CCCCCC; 339 | text-align: center; 340 | padding-bottom: 120px; 341 | padding-top: 90px; 342 | } 343 | 344 | #footer, #footer-push { 345 | height: 20px; 346 | } 347 | 348 | #footer { 349 | clear: both; 350 | border-top: solid 1px #999999; 351 | background-color: #CCCCCC; 352 | padding: 7px 10px; 353 | } 354 | 355 | #footer .footer-right { 356 | float: right; 357 | } 358 | 359 | .nodata.row, .importinprogress.row, .errormessage.row { 360 | margin-top: 50px; 361 | margin-bottom: 20px; 362 | } 363 | 364 | .nodata h2, .importinprogress h2, .errormessage h2 { 365 | margin-top: 25px; 366 | margin-bottom: 7px; 367 | } 368 | 369 | .nodata li { 370 | color: inherit; 371 | border-bottom: 1px solid #F2F2F2; 372 | padding-bottom: 7px; 373 | margin-bottom: 7px; 374 | } 375 | 376 | .nodata li:last-of-type { 377 | border-bottom: none; 378 | padding-bottom: inherit; 379 | margin-bottom: inherit; 380 | } 381 | 382 | .nodata pre { 383 | margin-top: 7px; 384 | } 385 | 386 | p.page-actions { 387 | padding-top: 25px; 388 | } 389 | 390 | .importinprogress .subinfo, .errormessage .subinfo { 391 | color: #999999; 392 | } 393 | 394 | .collapsible-header._list-item:before { 395 | margin: 1rem 0.8rem; 396 | margin-left: -0.4rem; 397 | } 398 | 399 | html { 400 | font-size: 100%; 401 | } -------------------------------------------------------------------------------- /app/css/zest-devdocs.css.scss: -------------------------------------------------------------------------------- 1 | //= depend_on icons.png 2 | //= depend_on icons@2x.png 3 | 4 | //= require vendor/open-sans 5 | 6 | /*! 7 | * Copyright 2013-2016 Thibaut Courouble and other contributors 8 | * 9 | * This source code is licensed under the terms of the Mozilla 10 | * Public License, v. 2.0, a copy of which may be obtained at: 11 | * http://mozilla.org/MPL/2.0/ 12 | */ 13 | 14 | @import 'global/variables', 15 | 'global/icons', 16 | 'global/classes', 17 | 'global/base'; 18 | 19 | @import 'components/app', 20 | 'components/content', 21 | 'components/sidebar'; 22 | 23 | @import 'pages/base', 24 | 'pages/angular', 25 | 'pages/apache', 26 | 'pages/bower', 27 | 'pages/c', 28 | 'pages/cakephp', 29 | 'pages/chai', 30 | 'pages/clojure', 31 | 'pages/coffeescript', 32 | 'pages/d3', 33 | 'pages/dojo', 34 | 'pages/drupal', 35 | 'pages/elixir', 36 | 'pages/ember', 37 | 'pages/erlang', 38 | 'pages/express', 39 | 'pages/git', 40 | 'pages/github', 41 | 'pages/go', 42 | 'pages/haskell', 43 | 'pages/jquery', 44 | 'pages/knockout', 45 | 'pages/laravel', 46 | 'pages/lua', 47 | 'pages/mdn', 48 | 'pages/meteor', 49 | 'pages/modernizr', 50 | 'pages/moment', 51 | 'pages/nginx', 52 | 'pages/node', 53 | 'pages/npm', 54 | 'pages/phalcon', 55 | 'pages/phaser', 56 | 'pages/php', 57 | 'pages/phpunit', 58 | 'pages/postgres', 59 | 'pages/ramda', 60 | 'pages/rdoc', 61 | 'pages/react', 62 | 'pages/redis', 63 | 'pages/requirejs', 64 | 'pages/rethinkdb', 65 | 'pages/rfc', 66 | 'pages/rust', 67 | 'pages/socketio', 68 | 'pages/sphinx', 69 | 'pages/sphinx_simple', 70 | 'pages/tcl_tk', 71 | 'pages/tensorflow', 72 | 'pages/underscore', 73 | 'pages/vagrant', 74 | 'pages/vue', 75 | 'pages/yard', 76 | 'pages/yii'; 77 | -------------------------------------------------------------------------------- /app/example.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev-tools": true 3 | } 4 | -------------------------------------------------------------------------------- /app/img/logo.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/img/logo.icns -------------------------------------------------------------------------------- /app/img/logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/img/logo.ico -------------------------------------------------------------------------------- /app/img/logo_96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/app/img/logo_96x96.png -------------------------------------------------------------------------------- /app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | zest 6 | 7 | 8 | 9 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "zest", 3 | "version" : "0.0-DEV", 4 | "build-commit" : "0000", 5 | "build-date" : "0000-00-00", 6 | "main" : "app.js", 7 | "private": true 8 | } 9 | -------------------------------------------------------------------------------- /app/prod.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "dev-tools": false 3 | } 4 | -------------------------------------------------------------------------------- /app/sotags.json: -------------------------------------------------------------------------------- 1 | ["2d", 2 | "3d", 3 | "64bit", 4 | "access-vba", 5 | "action", 6 | "actionbarsherlock", 7 | "actionscript", 8 | "actionscript-3", 9 | "active-directory", 10 | "activemq", 11 | "activerecord", 12 | "activex", 13 | "adb", 14 | "admob", 15 | "adobe", 16 | "ado.net", 17 | "aes", 18 | "afnetworking", 19 | "air", 20 | "ajax", 21 | "akka", 22 | "algorithm", 23 | "alignment", 24 | "amazon-ec2", 25 | "amazon-s3", 26 | "amazon-web-services", 27 | "anchor", 28 | "android", 29 | "android-actionbar", 30 | "android-activity", 31 | "android-animation", 32 | "android-asynctask", 33 | "android-camera", 34 | "android-edittext", 35 | "android-emulator", 36 | "android-fragments", 37 | "android-gradle", 38 | "android-intent", 39 | "android-layout", 40 | "android-linearlayout", 41 | "android-listview", 42 | "android-manifest", 43 | "android-ndk", 44 | "android-service", 45 | "android-sqlite", 46 | "android-studio", 47 | "android-viewpager", 48 | "android-webview", 49 | "android-widget", 50 | "angularjs", 51 | "angularjs-directive", 52 | "angularjs-ng-repeat", 53 | "angularjs-scope", 54 | "angular-ui-router", 55 | "animation", 56 | "annotations", 57 | "ant", 58 | "apache", 59 | "apache2", 60 | "apache-camel", 61 | "apache-pig", 62 | "apache-poi", 63 | "apache-spark", 64 | "api", 65 | "apk", 66 | "append", 67 | "apple-push-notifications", 68 | "applescript", 69 | "applet", 70 | "app-store", 71 | "architecture", 72 | "arduino", 73 | "arguments", 74 | "arm", 75 | "arraylist", 76 | "arrays", 77 | "artificial-intelligence", 78 | "ascii", 79 | "asp-classic", 80 | "asp.net", 81 | "asp.net-ajax", 82 | "asp.net-membership", 83 | "asp.net-mvc", 84 | "asp.net-mvc-2", 85 | "asp.net-mvc-3", 86 | "asp.net-mvc-4", 87 | "asp.net-mvc-5", 88 | "asp.net-mvc-routing", 89 | "asp.net-web-api", 90 | "asp.net-web-api2", 91 | "assembly", 92 | "associations", 93 | "async-await", 94 | "asynchronous", 95 | "attributes", 96 | "audio", 97 | "authentication", 98 | "authorization", 99 | "autocomplete", 100 | "autolayout", 101 | "automated-tests", 102 | "automatic-ref-counting", 103 | "automation", 104 | "avfoundation", 105 | "awk", 106 | "awt", 107 | "azure", 108 | "backbone.js", 109 | "background", 110 | "background-image", 111 | "backup", 112 | "base64", 113 | "bash", 114 | "batch-file", 115 | "beautifulsoup", 116 | "binary", 117 | "binding", 118 | "bit-manipulation", 119 | "bitmap", 120 | "blackberry", 121 | "blob", 122 | "bluetooth", 123 | "boolean", 124 | "boost", 125 | "border", 126 | "branch", 127 | "broadcastreceiver", 128 | "browser", 129 | "buffer", 130 | "build", 131 | "bundle", 132 | "button", 133 | "byte", 134 | "bytearray", 135 | "c", 136 | "c%23", 137 | "c%23-3.0", 138 | "c%23-4.0", 139 | "c%2b%2b", 140 | "c%2b%2b11", 141 | "c%2b%2b-cli", 142 | "caching", 143 | "cakephp", 144 | "cakephp-2.0", 145 | "calendar", 146 | "call", 147 | "callback", 148 | "camera", 149 | "canvas", 150 | "capybara", 151 | "case", 152 | "cassandra", 153 | "casting", 154 | "celery", 155 | "centos", 156 | "certificate", 157 | "cgi", 158 | "char", 159 | "character", 160 | "character-encoding", 161 | "charts", 162 | "chat", 163 | "checkbox", 164 | "chef", 165 | "ckeditor", 166 | "clang", 167 | "class", 168 | "classpath", 169 | "click", 170 | "client", 171 | "client-server", 172 | "clojure", 173 | "closures", 174 | "cloud", 175 | "cmake", 176 | "cmd", 177 | "cocoa", 178 | "cocoa-touch", 179 | "cocos2d-iphone", 180 | "cocos2d-x", 181 | "codeigniter", 182 | "coding-style", 183 | "coffeescript", 184 | "coldfusion", 185 | "collections", 186 | "colors", 187 | "com", 188 | "combobox", 189 | "command", 190 | "command-line", 191 | "comments", 192 | "common-lisp", 193 | "compare", 194 | "comparison", 195 | "compilation", 196 | "compiler-construction", 197 | "compiler-errors", 198 | "components", 199 | "composer-php", 200 | "compression", 201 | "computer-vision", 202 | "concatenation", 203 | "concurrency", 204 | "conditional", 205 | "configuration", 206 | "connection", 207 | "console", 208 | "console-application", 209 | "const", 210 | "constraints", 211 | "constructor", 212 | "containers", 213 | "content-management-system", 214 | "contextmenu", 215 | "continuous-integration", 216 | "control", 217 | "controller", 218 | "converter", 219 | "cookies", 220 | "coordinates", 221 | "copy", 222 | "cordova", 223 | "core-animation", 224 | "core-data", 225 | "core-graphics", 226 | "cors", 227 | "couchdb", 228 | "count", 229 | "crash", 230 | "cron", 231 | "cross-browser", 232 | "cross-domain", 233 | "cross-platform", 234 | "cryptography", 235 | "crystal-reports", 236 | "css", 237 | "css3", 238 | "css-float", 239 | "css-position", 240 | "css-selectors", 241 | "css-transitions", 242 | "csv", 243 | "cucumber", 244 | "cuda", 245 | "curl", 246 | "cursor", 247 | "custom-controls", 248 | "cxf", 249 | "cygwin", 250 | "cypher", 251 | "d3.js", 252 | "dart", 253 | "database", 254 | "database-connection", 255 | "database-design", 256 | "data-binding", 257 | "data.frame", 258 | "dataframes", 259 | "datagrid", 260 | "datagridview", 261 | "dataset", 262 | "data-structures", 263 | "datatable", 264 | "data.table", 265 | "datatables", 266 | "date", 267 | "datepicker", 268 | "datetime", 269 | "db2", 270 | "debian", 271 | "debugging", 272 | "decimal", 273 | "delegates", 274 | "delphi", 275 | "dependencies", 276 | "dependency-injection", 277 | "deployment", 278 | "deserialization", 279 | "design", 280 | "design-patterns", 281 | "devexpress", 282 | "devise", 283 | "dialog", 284 | "dictionary", 285 | "directory", 286 | "directx", 287 | "django", 288 | "django-admin", 289 | "django-forms", 290 | "django-models", 291 | "django-rest-framework", 292 | "django-templates", 293 | "django-views", 294 | "dll", 295 | "dns", 296 | "docker", 297 | "doctrine", 298 | "doctrine2", 299 | "documentation", 300 | "dojo", 301 | "dom", 302 | "domain-driven-design", 303 | "double", 304 | "download", 305 | "drag-and-drop", 306 | "drawing", 307 | "driver", 308 | "drop-down-menu", 309 | "drupal", 310 | "drupal-6", 311 | "drupal-7", 312 | "duplicates", 313 | "dynamic", 314 | "dynamics-crm-2011", 315 | "echo", 316 | "eclipse", 317 | "eclipselink", 318 | "eclipse-plugin", 319 | "eclipse-rcp", 320 | "e-commerce", 321 | "editor", 322 | "ef-code-first", 323 | "ejb", 324 | "elasticsearch", 325 | "elisp", 326 | "eloquent", 327 | "emacs", 328 | "email", 329 | "embedded", 330 | "ember-data", 331 | "ember.js", 332 | "encoding", 333 | "encryption", 334 | "entity", 335 | "entity-framework", 336 | "entity-framework-4", 337 | "entity-framework-5", 338 | "entity-framework-6", 339 | "enums", 340 | "environment-variables", 341 | "erlang", 342 | "error-handling", 343 | "escaping", 344 | "event-handling", 345 | "events", 346 | "excel", 347 | "excel-2010", 348 | "excel-formula", 349 | "excel-vba", 350 | "exception", 351 | "exception-handling", 352 | "exec", 353 | "export", 354 | "express", 355 | "expression", 356 | "extjs", 357 | "extjs4", 358 | "f%23", 359 | "facebook", 360 | "facebook-graph-api", 361 | "facebook-javascript-sdk", 362 | "facebook-like", 363 | "fancybox", 364 | "ffmpeg", 365 | "field", 366 | "file", 367 | "file-io", 368 | "filesystems", 369 | "file-upload", 370 | "filter", 371 | "filtering", 372 | "find", 373 | "firebase", 374 | "firefox", 375 | "firefox-addon", 376 | "flash", 377 | "flask", 378 | "flex", 379 | "flex4", 380 | "floating-point", 381 | "fluent-nhibernate", 382 | "focus", 383 | "folder", 384 | "fonts", 385 | "foreach", 386 | "foreign-keys", 387 | "fork", 388 | "for-loop", 389 | "format", 390 | "formatting", 391 | "forms", 392 | "fortran", 393 | "fragment", 394 | "frameworks", 395 | "ftp", 396 | "fullcalendar", 397 | "full-text-search", 398 | "function", 399 | "functional-programming", 400 | "g%2b%2b", 401 | "gae-datastore", 402 | "garbage-collection", 403 | "gcc", 404 | "gdb", 405 | "gem", 406 | "generics", 407 | "geolocation", 408 | "geometry", 409 | "get", 410 | "ggplot2", 411 | "git", 412 | "github", 413 | "glassfish", 414 | "global-variables", 415 | "glsl", 416 | "gmail", 417 | "gnuplot", 418 | "go", 419 | "google-analytics", 420 | "google-api", 421 | "google-app-engine", 422 | "google-apps-script", 423 | "google-chrome", 424 | "google-chrome-extension", 425 | "google-cloud-messaging", 426 | "google-drive-sdk", 427 | "google-maps", 428 | "google-maps-api-3", 429 | "google-play", 430 | "google-play-services", 431 | "google-plus", 432 | "google-spreadsheet", 433 | "google-visualization", 434 | "gorm", 435 | "gps", 436 | "gradle", 437 | "grails", 438 | "graph", 439 | "graphics", 440 | "grep", 441 | "grid", 442 | "gridview", 443 | "groovy", 444 | "group-by", 445 | "gruntjs", 446 | "gson", 447 | "gtk", 448 | "gulp", 449 | "gwt", 450 | "gzip", 451 | "hadoop", 452 | "handlebars.js", 453 | "hash", 454 | "hashmap", 455 | "haskell", 456 | "hbase", 457 | "hdfs", 458 | "header", 459 | "heap", 460 | "height", 461 | "heroku", 462 | "hex", 463 | "hibernate", 464 | "hide", 465 | "highcharts", 466 | "hive", 467 | "hook", 468 | "hosting", 469 | "hover", 470 | "hql", 471 | ".htaccess", 472 | "html", 473 | "html5", 474 | "html5-canvas", 475 | "html5-video", 476 | "html-lists", 477 | "html-parsing", 478 | "html-table", 479 | "http", 480 | "http-headers", 481 | "http-post", 482 | "httprequest", 483 | "https", 484 | "http-status-code-404", 485 | "httpwebrequest", 486 | "hyperlink", 487 | "icons", 488 | "ide", 489 | "iframe", 490 | "if-statement", 491 | "iis", 492 | "iis-7", 493 | "iis-7.5", 494 | "image", 495 | "imagemagick", 496 | "image-processing", 497 | "imageview", 498 | "import", 499 | "in-app-purchase", 500 | "include", 501 | "indexing", 502 | "inheritance", 503 | "initialization", 504 | "input", 505 | "insert", 506 | "install", 507 | "installation", 508 | "installer", 509 | "int", 510 | "integer", 511 | "intellij-idea", 512 | "interface", 513 | "interface-builder", 514 | "internationalization", 515 | "internet-explorer", 516 | "internet-explorer-7", 517 | "internet-explorer-8", 518 | "internet-explorer-9", 519 | "interop", 520 | "io", 521 | "ionic", 522 | "ionic-framework", 523 | "ios", 524 | "ios4", 525 | "ios5", 526 | "ios6", 527 | "ios7", 528 | "ios8", 529 | "ios9", 530 | "ios-simulator", 531 | "ip", 532 | "ipad", 533 | "iphone", 534 | "ipython", 535 | "iteration", 536 | "iterator", 537 | "itext", 538 | "itextsharp", 539 | "itunesconnect", 540 | "jackson", 541 | "jade", 542 | "jar", 543 | "jasmine", 544 | "jasper-reports", 545 | "java", 546 | "java-8", 547 | "java-ee", 548 | "javafx", 549 | "javafx-2", 550 | "java-me", 551 | "javascript", 552 | "javascript-events", 553 | "java.util.scanner", 554 | "jaxb", 555 | "jax-rs", 556 | "jax-ws", 557 | "jboss", 558 | "jbutton", 559 | "jdbc", 560 | "jenkins", 561 | "jersey", 562 | "jetty", 563 | "jframe", 564 | "jmeter", 565 | "jms", 566 | "jni", 567 | "join", 568 | "joomla", 569 | "jpa", 570 | "jpanel", 571 | "jqgrid", 572 | "jquery", 573 | "jquery-animate", 574 | "jquery-mobile", 575 | "jquery-plugins", 576 | "jquery-selectors", 577 | "jquery-ui", 578 | "jquery-validate", 579 | "jsf", 580 | "jsf-2", 581 | "json", 582 | "json.net", 583 | "jsonp", 584 | "jsoup", 585 | "jsp", 586 | "jstl", 587 | "jtable", 588 | "junit", 589 | "jvm", 590 | "kendo-grid", 591 | "kendo-ui", 592 | "kernel", 593 | "key", 594 | "keyboard", 595 | "knockout.js", 596 | "label", 597 | "lambda", 598 | "language-agnostic", 599 | "laravel", 600 | "laravel-4", 601 | "laravel-5", 602 | "latex", 603 | "layout", 604 | "ldap", 605 | "left-join", 606 | "less", 607 | "libgdx", 608 | "liferay", 609 | "line", 610 | "linked-list", 611 | "linker", 612 | "linq", 613 | "linq-to-entities", 614 | "linq-to-sql", 615 | "linq-to-xml", 616 | "linux", 617 | "linux-kernel", 618 | "lisp", 619 | "list", 620 | "listbox", 621 | "listener", 622 | "listview", 623 | "load", 624 | "localhost", 625 | "localization", 626 | "local-storage", 627 | "location", 628 | "locking", 629 | "log4j", 630 | "logging", 631 | "logic", 632 | "login", 633 | "loops", 634 | "lua", 635 | "lucene", 636 | "machine-learning", 637 | "macros", 638 | "magento", 639 | "magento-1.7", 640 | "make", 641 | "makefile", 642 | "malloc", 643 | "many-to-many", 644 | "map", 645 | "mapkit", 646 | "mapping", 647 | "mapreduce", 648 | "maps", 649 | "match", 650 | "math", 651 | "matlab", 652 | "matplotlib", 653 | "matrix", 654 | "maven", 655 | "maven-2", 656 | "max", 657 | "media-queries", 658 | "memcached", 659 | "memory", 660 | "memory-leaks", 661 | "memory-management", 662 | "menu", 663 | "mercurial", 664 | "merge", 665 | "metadata", 666 | "meteor", 667 | "methods", 668 | "mfc", 669 | "microsoft-metro", 670 | "migration", 671 | "mingw", 672 | "mkmapview", 673 | "mobile", 674 | "mobile-safari", 675 | "mocking", 676 | "mockito", 677 | "modal-dialog", 678 | "model", 679 | "model-view-controller", 680 | "mod-rewrite", 681 | "module", 682 | "mongodb", 683 | "mongodb-query", 684 | "mongoid", 685 | "mongoose", 686 | "mono", 687 | "monodroid", 688 | "monotouch", 689 | "mouseevent", 690 | "mp3", 691 | "mpi", 692 | "ms-access", 693 | "ms-access-2007", 694 | "ms-access-2010", 695 | "msbuild", 696 | "ms-office", 697 | "ms-word", 698 | "mule", 699 | "multidimensional-array", 700 | "multiprocessing", 701 | "multithreading", 702 | "mvvm", 703 | "mysql", 704 | "mysqli", 705 | "namespaces", 706 | "navigation", 707 | "neo4j", 708 | "nested", 709 | ".net", 710 | ".net-3.5", 711 | ".net-4.0", 712 | "netbeans", 713 | "networking", 714 | "network-programming", 715 | "neural-network", 716 | "nginx", 717 | "nhibernate", 718 | "ninject", 719 | "nlp", 720 | "node.js", 721 | "nosql", 722 | "notepad%2b%2b", 723 | "notifications", 724 | "npm", 725 | "nsarray", 726 | "nsdate", 727 | "nsdictionary", 728 | "nsmutablearray", 729 | "nsstring", 730 | "nuget", 731 | "null", 732 | "nullpointerexception", 733 | "numbers", 734 | "numpy", 735 | "nunit", 736 | "oauth", 737 | "oauth-2.0", 738 | "object", 739 | "objective-c", 740 | "ocaml", 741 | "odata", 742 | "odbc", 743 | "onclick", 744 | "oop", 745 | "opencart", 746 | "opencl", 747 | "opencv", 748 | "openerp", 749 | "opengl", 750 | "opengl-es", 751 | "opengl-es-2.0", 752 | "openshift", 753 | "open-source", 754 | "openssl", 755 | "operating-system", 756 | "operator-overloading", 757 | "operators", 758 | "optimization", 759 | "oracle", 760 | "oracle10g", 761 | "oracle11g", 762 | "order", 763 | "orientation", 764 | "orm", 765 | "osgi", 766 | "osx", 767 | "outlook", 768 | "out-of-memory", 769 | "output", 770 | "overflow", 771 | "override", 772 | "package", 773 | "pagination", 774 | "pandas", 775 | "paperclip", 776 | "parallel-processing", 777 | "parameter-passing", 778 | "parameters", 779 | "parse.com", 780 | "parsing", 781 | "passwords", 782 | "path", 783 | "pattern-matching", 784 | "paypal", 785 | "pdf", 786 | "pdf-generation", 787 | "pdo", 788 | "performance", 789 | "perl", 790 | "permissions", 791 | "persistence", 792 | "phantomjs", 793 | "phonegap-plugins", 794 | "php", 795 | "phpmyadmin", 796 | "phpunit", 797 | "pip", 798 | "pipe", 799 | "pivot", 800 | "playframework", 801 | "playframework-2.0", 802 | "plot", 803 | "plsql", 804 | "plugins", 805 | "png", 806 | "pointers", 807 | "polymer", 808 | "polymorphism", 809 | "popup", 810 | "port", 811 | "position", 812 | "posix", 813 | "post", 814 | "postgresql", 815 | "powershell", 816 | "preg-match", 817 | "preg-replace", 818 | "prepared-statement", 819 | "primefaces", 820 | "printf", 821 | "printing", 822 | "process", 823 | "profiling", 824 | "programming-languages", 825 | "progress-bar", 826 | "prolog", 827 | "promise", 828 | "properties", 829 | "prototype", 830 | "protractor", 831 | "proxy", 832 | "pthreads", 833 | "push", 834 | "push-notification", 835 | "pygame", 836 | "pyqt", 837 | "pyqt4", 838 | "python", 839 | "python-2.7", 840 | "python-3.x", 841 | "qml", 842 | "qt", 843 | "qt4", 844 | "query-optimization", 845 | "queue", 846 | "r", 847 | "rabbitmq", 848 | "radio-button", 849 | "rake", 850 | "random", 851 | "range", 852 | "raspberry-pi", 853 | "razor", 854 | "reactjs", 855 | "recursion", 856 | "redirect", 857 | "redis", 858 | "refactoring", 859 | "reference", 860 | "reflection", 861 | "refresh", 862 | "regex", 863 | "registry", 864 | "relational-database", 865 | "rendering", 866 | "replace", 867 | "report", 868 | "reporting-services", 869 | "repository", 870 | "request", 871 | "requirejs", 872 | "resharper", 873 | "resize", 874 | "resources", 875 | "responsive-design", 876 | "rest", 877 | "return", 878 | "rewrite", 879 | "richfaces", 880 | "rotation", 881 | "routes", 882 | "routing", 883 | "row", 884 | "rsa", 885 | "rspec", 886 | "rss", 887 | "ruby", 888 | "rubygems", 889 | "ruby-on-rails", 890 | "ruby-on-rails-3", 891 | "ruby-on-rails-3.1", 892 | "ruby-on-rails-3.2", 893 | "ruby-on-rails-4", 894 | "runtime", 895 | "runtime-error", 896 | "rust", 897 | "rvm", 898 | "safari", 899 | "sails.js", 900 | "salesforce", 901 | "sas", 902 | "sass", 903 | "save", 904 | "sbt", 905 | "scala", 906 | "scheduled-tasks", 907 | "schema", 908 | "scheme", 909 | "scikit-learn", 910 | "scipy", 911 | "scope", 912 | "scrapy", 913 | "screen", 914 | "scripting", 915 | "scroll", 916 | "scrollbar", 917 | "scrollview", 918 | "sdk", 919 | "sdl", 920 | "search", 921 | "security", 922 | "sed", 923 | "segmentation-fault", 924 | "select", 925 | "selenium", 926 | "selenium-webdriver", 927 | "sencha-touch", 928 | "sencha-touch-2", 929 | "seo", 930 | "serialization", 931 | "serial-port", 932 | "server", 933 | "service", 934 | "servicestack", 935 | "servlets", 936 | "session", 937 | "set", 938 | "settings", 939 | "shader", 940 | "shared-libraries", 941 | "sharedpreferences", 942 | "sharepoint", 943 | "sharepoint-2007", 944 | "sharepoint-2010", 945 | "sharepoint-2013", 946 | "shell", 947 | "shiny", 948 | "signalr", 949 | "signals", 950 | "silverlight", 951 | "silverlight-4.0", 952 | "sinatra", 953 | "single-sign-on", 954 | "singleton", 955 | "sitecore", 956 | "size", 957 | "slider", 958 | "smarty", 959 | "sms", 960 | "smtp", 961 | "soap", 962 | "socket.io", 963 | "sockets", 964 | "solr", 965 | "sonarqube", 966 | "sorting", 967 | "spinner", 968 | "split", 969 | "spring", 970 | "spring-boot", 971 | "spring-data", 972 | "spring-mvc", 973 | "spring-security", 974 | "sprite", 975 | "sprite-kit", 976 | "sql", 977 | "sqlalchemy", 978 | "sqlite", 979 | "sqlite3", 980 | "sql-order-by", 981 | "sql-server", 982 | "sql-server-2005", 983 | "sql-server-2008", 984 | "sql-server-2008-r2", 985 | "sql-server-2012", 986 | "sql-server-ce", 987 | "sql-update", 988 | "ssh", 989 | "ssis", 990 | "ssl", 991 | "ssl-certificate", 992 | "ssrs-2008", 993 | "stack", 994 | "static", 995 | "statistics", 996 | "stl", 997 | "storage", 998 | "stored-procedures", 999 | "storyboard", 1000 | "stream", 1001 | "streaming", 1002 | "string", 1003 | "struct", 1004 | "structure", 1005 | "struts", 1006 | "struts2", 1007 | "styles", 1008 | "subdomain", 1009 | "sublimetext2", 1010 | "submit", 1011 | "subprocess", 1012 | "subquery", 1013 | "substring", 1014 | "sum", 1015 | "svg", 1016 | "svn", 1017 | "swift", 1018 | "swift2", 1019 | "swing", 1020 | "switch-statement", 1021 | "swt", 1022 | "symfony1", 1023 | "symfony2", 1024 | "synchronization", 1025 | "syntax", 1026 | "syntax-error", 1027 | "table", 1028 | "tableview", 1029 | "tabs", 1030 | "tags", 1031 | "task", 1032 | "task-parallel-library", 1033 | "tcl", 1034 | "tcp", 1035 | "tdd", 1036 | "teamcity", 1037 | "telerik", 1038 | "templates", 1039 | "terminal", 1040 | "testing", 1041 | "testng", 1042 | "text", 1043 | "textarea", 1044 | "textbox", 1045 | "text-files", 1046 | "textures", 1047 | "textview", 1048 | "tfs", 1049 | "tfs2010", 1050 | "themes", 1051 | "this", 1052 | "thread-safety", 1053 | "three.js", 1054 | "time", 1055 | "timeout", 1056 | "timer", 1057 | "time-series", 1058 | "timestamp", 1059 | "timezone", 1060 | "tinymce", 1061 | "titanium", 1062 | "tkinter", 1063 | "toggle", 1064 | "tomcat", 1065 | "tomcat7", 1066 | "tooltip", 1067 | "tortoisesvn", 1068 | "touch", 1069 | "transactions", 1070 | "tree", 1071 | "treeview", 1072 | "triggers", 1073 | "try-catch", 1074 | "tsql", 1075 | "tuples", 1076 | "twig", 1077 | "twitter", 1078 | "twitter-bootstrap", 1079 | "twitter-bootstrap-3", 1080 | "type-conversion", 1081 | "types", 1082 | "typescript", 1083 | "typo3", 1084 | "ubuntu", 1085 | "udp", 1086 | "uibutton", 1087 | "uicollectionview", 1088 | "uiimage", 1089 | "uiimageview", 1090 | "uikit", 1091 | "uilabel", 1092 | "uinavigationbar", 1093 | "uinavigationcontroller", 1094 | "uiscrollview", 1095 | "uitabbarcontroller", 1096 | "uitableview", 1097 | "uitextfield", 1098 | "uitextview", 1099 | "uiview", 1100 | "uiviewcontroller", 1101 | "uiwebview", 1102 | "uml", 1103 | "undefined", 1104 | "underscore.js", 1105 | "unicode", 1106 | "unit-testing", 1107 | "unity3d", 1108 | "unix", 1109 | "upload", 1110 | "uri", 1111 | "url", 1112 | "url-rewriting", 1113 | "usb", 1114 | "user", 1115 | "user-controls", 1116 | "user-interface", 1117 | "utf-8", 1118 | "vagrant", 1119 | "validation", 1120 | "variables", 1121 | "vb6", 1122 | "vba", 1123 | "vb.net", 1124 | "vbscript", 1125 | "vector", 1126 | "version", 1127 | "version-control", 1128 | "video", 1129 | "video-streaming", 1130 | "view", 1131 | "views", 1132 | "vim", 1133 | "virtual-machine", 1134 | "visual-c%2b%2b", 1135 | "visual-studio", 1136 | "visual-studio-2008", 1137 | "visual-studio-2010", 1138 | "visual-studio-2012", 1139 | "visual-studio-2013", 1140 | "visual-studio-2015", 1141 | "vsto", 1142 | "wamp", 1143 | "warnings", 1144 | "wcf", 1145 | "web", 1146 | "web-applications", 1147 | "webbrowser-control", 1148 | "web-config", 1149 | "web-crawler", 1150 | "webdriver", 1151 | "webforms", 1152 | "webgl", 1153 | "webkit", 1154 | "weblogic", 1155 | "web-scraping", 1156 | "webserver", 1157 | "web-services", 1158 | "website", 1159 | "websocket", 1160 | "websphere", 1161 | "webview", 1162 | "while-loop", 1163 | "widget", 1164 | "width", 1165 | "wifi", 1166 | "winapi", 1167 | "window", 1168 | "windows", 1169 | "windows-7", 1170 | "windows-8", 1171 | "windows-8.1", 1172 | "windows-installer", 1173 | "windows-mobile", 1174 | "windows-phone", 1175 | "windows-phone-7", 1176 | "windows-phone-8", 1177 | "windows-phone-8.1", 1178 | "windows-runtime", 1179 | "windows-services", 1180 | "windows-store-apps", 1181 | "windows-xp", 1182 | "winforms", 1183 | "winrt-xaml", 1184 | "wix", 1185 | "wolfram-mathematica", 1186 | "woocommerce", 1187 | "wordpress", 1188 | "wordpress-plugin", 1189 | "wordpress-theming", 1190 | "workflow", 1191 | "worklight", 1192 | "wpf", 1193 | "wpf-controls", 1194 | "wsdl", 1195 | "wso2", 1196 | "wxpython", 1197 | "x86", 1198 | "xamarin", 1199 | "xaml", 1200 | "xampp", 1201 | "xcode", 1202 | "xcode4", 1203 | "xcode5", 1204 | "xcode6", 1205 | "xhtml", 1206 | "xml", 1207 | "xmlhttprequest", 1208 | "xml-parsing", 1209 | "xml-serialization", 1210 | "xmpp", 1211 | "xna", 1212 | "xpages", 1213 | "xpath", 1214 | "xsd", 1215 | "xslt", 1216 | "yii", 1217 | "yii2", 1218 | "youtube", 1219 | "youtube-api", 1220 | "zend-framework", 1221 | "zend-framework2", 1222 | "zip", 1223 | "zoom", 1224 | "zurb-foundation"] 1225 | -------------------------------------------------------------------------------- /app/templates/comments.handlebars: -------------------------------------------------------------------------------- 1 |
    2 | {{#each comments }} 3 |
  • default_comments_max %}class="hidden-comment"{% endif %} --}}> 4 | {{#if Score }} 5 |

    {{ Score }}

    6 | {{/if}} 7 |
    8 | {{ Text }} — 9 | 13 |
    14 |
  • 15 | {{/each}} 16 |
-------------------------------------------------------------------------------- /app/templates/post.handlebars: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | {{ post.Title }} 5 |

6 |
7 |
8 |

9 | {{ post.Score }} 10 |

11 |

vote{{#ifPlural post.Score }}s{{/ifPlural}}

12 |
13 |
14 |

15 | {{ post.answers.length }} 16 |

17 |

answer{{#ifPlural post.answers.length }}s{{/ifPlural}}

18 |
19 |
20 |
21 | {{{ post.Body }}} 22 |
23 | 41 | {{#if post.comments}} 42 |
43 | {{> renderComments }} 44 |
45 | {{/if}} 46 |
47 |
48 | 49 | {{#if post.ClosedDate}} 50 |
51 |
52 |

This question was closed by a moderator on {{ post.ClosedDate }}.

53 |
54 |
55 | {{/if}} 56 | 57 |
58 |
59 | {{#if post.answers}} 60 |

{{ post.answers.length }} answer{{#ifPlural post.answers.length}}s{{/ifPlural}}

61 |
    62 | {{#each post.answers }} 63 |
  • 64 | 65 |
    66 |
    67 |

    68 | {{ Score }} 69 |

    70 |

    vote{{#ifPlural Score}}s{{/ifPlural}}

    71 |
    72 | {{#if Accepted }} 73 |
    74 | Accepted answer 75 |
    76 | {{/if}} 77 |
    78 |
    79 | {{{ Body }}} 80 |
    81 | 102 | 103 |
    104 | {{#if comments }} 105 | {{> renderComments }} 106 | {{/if}} 107 |
    108 |
  • 109 | {{/each}} 110 |
111 | {{/if}} 112 | {{#unless post.answers}} 113 |

There are no answers for this question :(

114 | {{/unless}} 115 |
116 |
-------------------------------------------------------------------------------- /app/viewer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 |
13 |

Welcome to Zest! To download documentation, go to 14 | "" -> "Settings".

15 |
16 | 24 | 25 | -------------------------------------------------------------------------------- /app/viewer.js: -------------------------------------------------------------------------------- 1 | window.ipcRenderer = require('electron').ipcRenderer; 2 | window.osPlatform = process.platform; 3 | ipcRenderer.on('reset', function(event, className) { 4 | document.body.className = className; 5 | document.body.innerHTML = ''; 6 | }); 7 | ipcRenderer.on('add', function(event, tag, html, attrs) { 8 | var el; 9 | if (tag === 3) { 10 | el = document.createTextNode(html); 11 | } else { 12 | el = document.createElement(tag); 13 | el.innerHTML = html; 14 | for (var i = 0; i < attrs.length; ++i) { 15 | el.setAttribute(attrs[i].name, attrs[i].value); 16 | } 17 | } 18 | document.body.appendChild(el); 19 | }); 20 | ipcRenderer.on('hash', function(event, hash) { 21 | location.hash = hash; 22 | }); -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 0.1.1-appveyor{build} 2 | pull_requests: 3 | do_not_increment_build_number: true 4 | os: Visual Studio 2013 5 | platform: x64 6 | clone_folder: c:\zest_build 7 | install: 8 | - ps: >- 9 | Install-Product node 5.1.1 x64 10 | 11 | nuget install packages.config 12 | 13 | cmd /c "scripts\build_deps 2>&1" 14 | build_script: 15 | - cmd: scripts\build_app 16 | artifacts: 17 | - path: builds\zest-v*\zest-v*.exe 18 | cache: 19 | - C:\Libraries\boost_1_59_0\stage\lib 20 | - C:\Libraries\boost_1_59_0\bin.v2 21 | - LucenePlusPlus 22 | - libarchive 23 | - sogrep-src 24 | - nodelucene 25 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "nodelucene", 5 | "sources": [ "nodelucene/LuceneIndex.cc" ], 6 | "libraries": [ 7 | "-llucene++", 8 | "-llucene++-contrib", 9 | "-L/usr/local/lib", 10 | # for Circle CI: 11 | "-L/home/ubuntu/installprefix/lib/x86_64-linux-gnu", 12 | "-Wl,-rpath,\\$$ORIGIN/resources" 13 | ], 14 | "xcode_settings": { 15 | "OTHER_CFLAGS": [ 16 | "-std=c++11", "-stdlib=libc++", "-mmacosx-version-min=10.7", "-fexceptions" 17 | ], 18 | }, 19 | "cflags!": [ "-fno-exceptions", "-fno-rtti" ], 20 | "cflags_cc!": [ "-fno-exceptions", "-fno-rtti" ], 21 | "include_dirs": [ 22 | "/usr/local/include/lucene++", 23 | "/usr/local/include", 24 | # for Circle CI: 25 | "/home/ubuntu/installprefix/include/lucene++" 26 | ], 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /binding.gyp.appveyor: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "nodelucene", 5 | "sources": [ "nodelucene/LuceneIndex.cc" ], 6 | "libraries": [ 7 | "c:\\zest_build\\LucenePlusPlus\\build\\src\\core\\Release\\lucene++.lib", "c:\\zest_build\\LucenePlusPlus\\build\\src\\contrib\\Release\\lucene++-contrib.lib", 8 | "C:\\Libraries\\boost_1_59_0\\stage\\lib\\boost_filesystem-vc120-mt-1_59.lib", 9 | "C:\\Libraries\\boost_1_59_0\\stage\\lib\\boost_system-vc120-mt-1_59.lib" ], 10 | "xcode_settings": { 11 | "OTHER_CFLAGS": [ 12 | "-std=c++11", "-stdlib=libc++", "-mmacosx-version-min=10.7", "-fexceptions" 13 | ], 14 | }, 15 | "cflags!": [ "-fno-exceptions" ], 16 | "defines!": ["_HAS_EXCEPTIONS=0"], 17 | "defines": ["BOOST_ALL_NO_LIB"], 18 | 'configurations': { 19 | 'Release': { 20 | 'msvs_settings': { 21 | 'VCCLCompilerTool': { 22 | 'ExceptionHandling': 1 23 | }, 24 | 'VCLinkerTool': { 25 | 'AdditionalLibraryDirectories': 'C:\\Libraries\\boost_1_59_0\\stage\\lib' 26 | } 27 | } 28 | } 29 | }, 30 | "cflags_cc!": [ "-fno-exceptions" ], 31 | "include_dirs": [ 32 | "c:\\zest_build\\LucenePlusPlus\\include", 33 | "c:\\zest_build\\LucenePlusPlus\\src\\contrib\\include", 34 | "c:\\zest_build\\LucenePlusPlus\\build\\include", 35 | "C:\\Libraries\\boost_1_59_0" 36 | ], 37 | } 38 | ] 39 | } -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zest", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "Materialize": "https://github.com/zestdocs/materialize.git#v0.97.5.autocomplete", 6 | "jquery": ">=2.1.1" 7 | }, 8 | "license": "MIT", 9 | "private": true, 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "test", 15 | "tests", 16 | "spec" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 5.1.0 4 | dependencies: 5 | pre: 6 | - sudo apt-get update; sudo apt-get install cmake libxerces-c-dev libboost-date-time-dev libboost-filesystem-dev libboost-iostreams-dev libboost-regex-dev libboost-system-dev libboost-thread-dev libleveldb-dev 7 | override: 8 | - ./scripts/build_circle_deps.sh 9 | cache_directories: 10 | - ~/LucenePlusPlus 11 | - ~/libarchive 12 | - ~/patchelf-0.9 13 | test: 14 | override: 15 | - ./scripts/build_circle.sh -------------------------------------------------------------------------------- /env/dev/cljs/zest/dev.cljs: -------------------------------------------------------------------------------- 1 | (ns ^:figwheel-no-load zest.dev 2 | (:require [zest.core :as core])) 3 | 4 | (core/init!) 5 | -------------------------------------------------------------------------------- /env/prod/cljs/zest/prod.cljs: -------------------------------------------------------------------------------- 1 | (ns ^:figwheel-no-load zest.prod 2 | (:require [zest.core :as core])) 3 | 4 | (core/init!) 5 | -------------------------------------------------------------------------------- /externs/misc.js: -------------------------------------------------------------------------------- 1 | // Node.JS externs: https://github.com/dcodeIO/node.js-closure-compiler-externs 2 | 3 | var electron = {}; 4 | electron.dialog = function() {}; 5 | electron.app = function() {}; 6 | electron.ipcRenderer = function() {}; 7 | electron.on = function() {}; 8 | electron.send = function() {}; 9 | electron.remote = function() {}; 10 | electron.require = function() {}; 11 | electron.buildFromTemplate = function() {}; 12 | electron.popup = function() {}; 13 | electron.getCurrentWindow = function() {}; 14 | electron.showErrorBox = function() {}; 15 | electron.setTitle = function() {}; 16 | electron.setRepresentedFilename = function() {}; 17 | electron.showMessageBox = function() {}; 18 | electron.getPath = function() {}; 19 | electron.showSaveDialog = function() {}; 20 | electron.showOpenDialog = function() {}; 21 | 22 | var process = { 23 | platform: {} 24 | }; 25 | -------------------------------------------------------------------------------- /nodelucene/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | project(searcher) 3 | 4 | # from https://cmake.org/pipermail/cmake/2008-January/019321.html 5 | MACRO (APPEND_CMAKE_INSTALL_RPATH RPATH_DIRS) 6 | IF (NOT ${ARGC} EQUAL 1) 7 | MESSAGE(SEND_ERROR "APPEND_CMAKE_INSTALL_RPATH takes 1 argument") 8 | ENDIF (NOT ${ARGC} EQUAL 1) 9 | FOREACH ( RPATH_DIR ${RPATH_DIRS} ) 10 | IF ( NOT ${RPATH_DIR} STREQUAL "" ) 11 | FILE( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR ) 12 | STRING( SUBSTRING ${RPATH_DIR} 0 1 RPATH_FIRST_CHAR ) 13 | IF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 14 | # relative path; CMake handling for these is unclear, 15 | # add them directly to the linker line. Add both $ORIGIN 16 | # and $$ORIGIN to ensure correct behavior for exes and 17 | # shared libraries. 18 | SET ( RPATH_DIR "$ORIGIN/${RPATH_DIR}:$$ORIGIN/${RPATH_DIR}" ) 19 | SET ( CMAKE_EXE_LINKER_FLAGS 20 | "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" ) 21 | SET ( CMAKE_SHARED_LINKER_FLAGS 22 | "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" ) 23 | ELSE ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 24 | # absolute path 25 | SET ( CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:${RPATH_DIR}" ) 26 | ENDIF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 27 | ENDIF ( NOT ${RPATH_DIR} STREQUAL "" ) 28 | ENDFOREACH ( RPATH_DIR ) 29 | ENDMACRO ( APPEND_CMAKE_INSTALL_RPATH ) 30 | 31 | APPEND_CMAKE_INSTALL_RPATH(".") 32 | 33 | find_package(PkgConfig) 34 | find_package( 35 | Boost COMPONENTS 36 | date_time 37 | filesystem 38 | iostreams 39 | regex 40 | system 41 | thread 42 | REQUIRED) 43 | pkg_search_module(LUCENE REQUIRED liblucene++) 44 | pkg_search_module(LUCENE_CONTRIB REQUIRED liblucene++-contrib) 45 | 46 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 47 | 48 | set(SOURCE_FILES searcher.cc) 49 | 50 | link_directories( 51 | ${LUCENE_LIBRARY_DIRS} 52 | ${LUCENE_CONTRIB_LIBRARY_DIRS} 53 | ) 54 | add_executable(searcher ${SOURCE_FILES}) 55 | target_link_libraries( 56 | searcher 57 | ${LUCENE_LIBRARIES} 58 | ${LUCENE_CONTRIB_LIBRARIES} 59 | ${Boost_LIBRARIES} 60 | ${Boost_FILESYSTEM_LIBRARIES} 61 | ${Boost_IOSTREAMS_LIBRARIES} 62 | ${Boost_REGEX_LIBRARIES} 63 | ${Boost_SYSTEM_LIBRARIES} 64 | ${Boost_THREAD_LIBRARIES} 65 | ) 66 | target_include_directories( 67 | searcher 68 | PUBLIC 69 | "/usr/local/include/node" 70 | ${LUCENE_INCLUDE_DIRS} 71 | ${LUCENE_CONTRIB_INCLUDE_DIRS} 72 | ${Boost_INCLUDE_DIRS} 73 | ) 74 | target_compile_options( 75 | searcher 76 | PUBLIC 77 | ${LUCENE_CFLAGS_OTHER} 78 | ${LUCENE_CONTRIB_CFLAGS_OTHER} 79 | ) 80 | -------------------------------------------------------------------------------- /nodelucene/CMakeLists.txt.appveyor: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(searcher) 3 | 4 | find_package(PkgConfig) 5 | find_package( 6 | Boost COMPONENTS 7 | date_time 8 | filesystem 9 | regex 10 | system 11 | thread 12 | REQUIRED) 13 | set(Boost_USE_STATIC_LIBS OFF) 14 | if(MSVC) 15 | # Disable automatic boost linking on Windows as libraries are added to the linker explicitly 16 | add_definitions(-DBOOST_ALL_NO_LIB) 17 | endif() 18 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 19 | 20 | set(SOURCE_FILES searcher.cc) 21 | 22 | link_directories( 23 | "C:\\Libraries\\boost_1_59_0\\stage\\lib" 24 | ) 25 | add_executable(searcher ${SOURCE_FILES}) 26 | target_link_libraries( 27 | searcher 28 | "c:\\zest_build\\LucenePlusPlus\\build\\src\\core\\Release\\lucene++.lib" 29 | "c:\\zest_build\\LucenePlusPlus\\build\\src\\contrib\\Release\\lucene++-contrib.lib" 30 | ${Boost_LIBRARIES} 31 | ${Boost_FILESYSTEM_LIBRARIES} 32 | "C:\\Libraries\\boost_1_59_0\\stage\\lib\\libboost_iostreams-vc120-mt-1_59.lib" 33 | ${Boost_REGEX_LIBRARIES} 34 | ${Boost_SYSTEM_LIBRARIES} 35 | ${Boost_THREAD_LIBRARIES} 36 | ) 37 | target_include_directories( 38 | searcher 39 | PUBLIC 40 | "/usr/local/include/node" 41 | "c:\\zest_build\\LucenePlusPlus\\include" 42 | "c:\\zest_build\\LucenePlusPlus\\src\\contrib\\include" 43 | "c:\\zest_build\\LucenePlusPlus\\build\\include" 44 | ${Boost_INCLUDE_DIRS} 45 | ) 46 | target_compile_options( 47 | searcher 48 | PUBLIC 49 | ${LUCENE_CFLAGS_OTHER} 50 | ${LUCENE_CONTRIB_CFLAGS_OTHER} 51 | ) 52 | -------------------------------------------------------------------------------- /nodelucene/LuceneIndex.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #define LPP_HAVE_DLL 7 | 8 | #include "LuceneIndex.h" 9 | #include "FileUtils.h" 10 | #include "FuzzyTermEnum.h" 11 | #include "Highlighter.h" 12 | #include "QueryScorer.h" 13 | #include "SimpleFragmenter.h" 14 | #include "SimpleHTMLFormatter.h" 15 | 16 | using namespace Lucene; 17 | 18 | namespace nodelucene { 19 | 20 | using v8::Function; 21 | using v8::FunctionCallbackInfo; 22 | using v8::FunctionTemplate; 23 | using v8::Isolate; 24 | using v8::Local; 25 | using v8::Number; 26 | using v8::Object; 27 | using v8::Persistent; 28 | using v8::String; 29 | using v8::Value; 30 | 31 | 32 | void InitAll(Local exports) { 33 | LuceneIndex::Init(exports); 34 | } 35 | 36 | NODE_MODULE(addon, InitAll) 37 | 38 | Persistent LuceneIndex::constructor; 39 | 40 | LuceneIndex::LuceneIndex(std::string name) { 41 | indexName = name; 42 | Lucene::String dirName(StringUtils::toUnicode(indexName)); 43 | if (!boost::filesystem::is_directory(dirName)) { 44 | // create empty index if missing 45 | indexWriter = newLucene( 46 | FSDirectory::open(dirName), 47 | newLucene(LuceneVersion::LUCENE_CURRENT), 48 | true, 49 | IndexWriter::MaxFieldLengthLIMITED 50 | ); 51 | indexWriter->optimize(); 52 | indexWriter->close(); 53 | } 54 | 55 | indexReader = IndexReader::open(FSDirectory::open(dirName), true); 56 | searcher = newLucene(indexReader); 57 | analyzer = newLucene(LuceneVersion::LUCENE_CURRENT); 58 | parser = newLucene(LuceneVersion::LUCENE_CURRENT, L"contents", analyzer); 59 | } 60 | 61 | 62 | 63 | LuceneIndex::~LuceneIndex() { 64 | } 65 | 66 | void LuceneIndex::Init(Local exports) { 67 | Isolate* isolate = exports->GetIsolate(); 68 | 69 | // Prepare constructor template 70 | Local tpl = FunctionTemplate::New(isolate, New); 71 | tpl->SetClassName(String::NewFromUtf8(isolate, "LuceneIndex")); 72 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 73 | 74 | // Prototype 75 | NODE_SET_PROTOTYPE_METHOD(tpl, "startWriting", StartWriting); 76 | NODE_SET_PROTOTYPE_METHOD(tpl, "addFile", AddFile); 77 | NODE_SET_PROTOTYPE_METHOD(tpl, "endWriting", EndWriting); 78 | NODE_SET_PROTOTYPE_METHOD(tpl, "search", Search); 79 | NODE_SET_PROTOTYPE_METHOD(tpl, "highlight", Highlight); 80 | NODE_SET_PROTOTYPE_METHOD(tpl, "suggestTerm", SuggestTerm); 81 | 82 | constructor.Reset(isolate, tpl->GetFunction()); 83 | exports->Set(String::NewFromUtf8(isolate, "LuceneIndex"), 84 | tpl->GetFunction()); 85 | } 86 | 87 | void LuceneIndex::New(const FunctionCallbackInfo& args) { 88 | Isolate* isolate = args.GetIsolate(); 89 | 90 | if (args.IsConstructCall()) { 91 | // Invoked as constructor: `new LuceneIndex(...)` 92 | std::string name = args[0]->IsUndefined() ? "SearchIndex" : *String::Utf8Value(args[0]); 93 | LuceneIndex * obj = new LuceneIndex(name); 94 | obj->Wrap(args.This()); 95 | args.GetReturnValue().Set(args.This()); 96 | } else { 97 | // Invoked as plain function `LuceneIndex(...)`, turn into construct call. 98 | const int argc = 1; 99 | Local argv[argc] = { args[0] }; 100 | Local cons = Local::New(isolate, constructor); 101 | args.GetReturnValue().Set(cons->NewInstance(argc, argv)); 102 | } 103 | } 104 | 105 | void LuceneIndex::AddFile(const FunctionCallbackInfo &args) { 106 | Isolate* isolate = args.GetIsolate(); 107 | 108 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 109 | 110 | if (!args[0]->IsString()) { 111 | args.GetReturnValue().Set( 112 | String::NewFromUtf8(isolate, "first arg must be string") 113 | ); 114 | return; 115 | } 116 | if (!args[1]->IsString()) { 117 | args.GetReturnValue().Set( 118 | String::NewFromUtf8(isolate, "second arg must be string") 119 | ); 120 | return; 121 | } 122 | 123 | Local fileName = args[0]->ToString(); 124 | Local contents = args[1]->ToString(); 125 | 126 | DocumentPtr doc = newLucene(); 127 | 128 | doc->add(newLucene( 129 | L"path", 130 | StringUtils::toUnicode(*String::Utf8Value(fileName)), 131 | Field::STORE_YES, 132 | Field::INDEX_NOT_ANALYZED 133 | )); 134 | doc->add(newLucene( 135 | L"contents", 136 | StringUtils::toUnicode(*String::Utf8Value(contents)), 137 | Field::STORE_NO, 138 | Field::INDEX_ANALYZED 139 | )); 140 | 141 | obj->indexWriter->addDocument(doc); 142 | 143 | args.GetReturnValue().Set( 144 | String::NewFromUtf8(isolate, "success!") 145 | ); 146 | } 147 | 148 | void LuceneIndex::StartWriting(const v8::FunctionCallbackInfo &args) { 149 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 150 | 151 | Lucene::String dirName(StringUtils::toUnicode(obj->indexName)); 152 | obj->indexWriter = newLucene( 153 | FSDirectory::open(dirName), 154 | newLucene(LuceneVersion::LUCENE_CURRENT), 155 | true, 156 | IndexWriter::MaxFieldLengthLIMITED 157 | ); 158 | } 159 | 160 | void LuceneIndex::EndWriting(const v8::FunctionCallbackInfo &args) { 161 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 162 | obj->indexWriter->optimize(); 163 | obj->indexWriter->close(); 164 | } 165 | 166 | void LuceneIndex::Search(const v8::FunctionCallbackInfo &args) { 167 | Isolate* isolate = args.GetIsolate(); 168 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 169 | 170 | if (!args[0]->IsString()) { 171 | args.GetReturnValue().Set( 172 | String::NewFromUtf8(isolate, "first arg must be string") 173 | ); 174 | return; 175 | } 176 | 177 | Local queryStr = args[0]->ToString(); 178 | Lucene::String queryLStr(StringUtils::toUnicode(*String::Utf8Value(queryStr))); 179 | 180 | TopScoreDocCollectorPtr collector = TopScoreDocCollector::create(10, false); 181 | 182 | Local ret = v8::Array::New(isolate); 183 | args.GetReturnValue().Set(ret); 184 | 185 | try { 186 | QueryPtr query = obj->parser->parse(queryLStr); 187 | obj->searcher->search(query, collector); 188 | 189 | Collection hits = collector->topDocs()->scoreDocs; 190 | 191 | for (int32_t i = 0; i < hits.size(); ++i) { 192 | DocumentPtr doc = obj->searcher->doc(hits[i]->doc); 193 | ret->Set(i, String::NewFromUtf8(isolate, (StringUtils::toUTF8(doc->get(L"path"))).c_str())); 194 | } 195 | } catch (std::exception const& e) { 196 | std::cerr << e.what() << std::endl; 197 | } catch (boost::exception const& e) { 198 | std::cerr << boost::diagnostic_information(e) << std::endl; 199 | } 200 | } 201 | 202 | void LuceneIndex::Highlight(const v8::FunctionCallbackInfo &args) { 203 | Isolate* isolate = args.GetIsolate(); 204 | 205 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 206 | 207 | if (!args[0]->IsString()) { 208 | args.GetReturnValue().Set( 209 | String::NewFromUtf8(isolate, "first arg must be string") 210 | ); 211 | return; 212 | } 213 | if (!args[1]->IsString()) { 214 | args.GetReturnValue().Set( 215 | String::NewFromUtf8(isolate, "second arg must be string") 216 | ); 217 | return; 218 | } 219 | 220 | Local contentsStr = args[0]->ToString(); 221 | Local queryStr = args[1]->ToString(); 222 | Lucene::String contentsLStr(StringUtils::toUnicode(*String::Utf8Value(contentsStr))); 223 | Lucene::String queryLStr(StringUtils::toUnicode(*String::Utf8Value(queryStr))); 224 | 225 | QueryPtr query = obj->parser->parse(queryLStr); 226 | 227 | FormatterPtr fmt = newLucene(); 228 | HighlighterScorerPtr scr = newLucene(query); 229 | Highlighter hl(fmt, scr); 230 | hl.setTextFragmenter(newLucene(500)); 231 | 232 | args.GetReturnValue().Set( 233 | String::NewFromUtf8( 234 | isolate, 235 | (StringUtils::toUTF8( 236 | hl.getBestFragment(obj->analyzer, L"contents", contentsLStr) 237 | )).c_str() 238 | ) 239 | ); 240 | } 241 | 242 | void LuceneIndex::SuggestTerm(const v8::FunctionCallbackInfo &args) { 243 | Isolate* isolate = args.GetIsolate(); 244 | 245 | LuceneIndex * obj = ObjectWrap::Unwrap(args.Holder()); 246 | 247 | if (!args[0]->IsString()) { 248 | args.GetReturnValue().Set( 249 | String::NewFromUtf8(isolate, "first arg must be string") 250 | ); 251 | return; 252 | } 253 | 254 | Local termNodeStr = args[0]->ToString(); 255 | std::string termStr(*String::Utf8Value(termNodeStr)); 256 | 257 | FuzzyTermEnum en( 258 | obj->indexReader, 259 | newLucene(L"contents", StringUtils::toUnicode(termStr.c_str())), 260 | 0.5 261 | ); 262 | 263 | int best = 0; 264 | std::string bestStr; 265 | while (en.next()) { 266 | if (en.docFreq() > best) { 267 | best = en.docFreq(); 268 | bestStr = StringUtils::toUTF8(en.term()->text()); 269 | } 270 | } 271 | 272 | args.GetReturnValue().Set( 273 | String::NewFromUtf8( 274 | isolate, 275 | bestStr.c_str() 276 | ) 277 | ); 278 | } 279 | 280 | } // namespace nodelucene -------------------------------------------------------------------------------- /nodelucene/LuceneIndex.h: -------------------------------------------------------------------------------- 1 | #ifndef NODELUCENE_LUCENEINDEX_H 2 | #define NODELUCENE_LUCENEINDEX_H 3 | 4 | #include 5 | #include 6 | 7 | #include "LuceneHeaders.h" 8 | 9 | namespace nodelucene { 10 | 11 | class LuceneIndex : public node::ObjectWrap { 12 | public: 13 | static void Init(v8::Local exports); 14 | 15 | private: 16 | explicit LuceneIndex(std::string name); 17 | ~LuceneIndex(); 18 | 19 | static void New(const v8::FunctionCallbackInfo& args); 20 | static void AddFile(const v8::FunctionCallbackInfo &args); 21 | static void StartWriting(const v8::FunctionCallbackInfo &args); 22 | static void EndWriting(const v8::FunctionCallbackInfo &args); 23 | static void Search(const v8::FunctionCallbackInfo &args); 24 | static void Highlight(const v8::FunctionCallbackInfo &args); 25 | static void SuggestTerm(const v8::FunctionCallbackInfo &args); 26 | static v8::Persistent constructor; 27 | 28 | std::string indexName; 29 | Lucene::IndexWriterPtr indexWriter; 30 | 31 | Lucene::IndexReaderPtr indexReader; 32 | Lucene::SearcherPtr searcher; 33 | Lucene::AnalyzerPtr analyzer; 34 | Lucene::QueryParserPtr parser; 35 | }; 36 | 37 | } // namespace demo 38 | 39 | #endif //NODELUCENE_LUCENEINDEX_H 40 | -------------------------------------------------------------------------------- /nodelucene/searcher.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include "LuceneHeaders.h" 7 | #include "FileUtils.h" 8 | #include "FuzzyTermEnum.h" 9 | #include "Highlighter.h" 10 | #include "QueryScorer.h" 11 | #include "SimpleFragmenter.h" 12 | #include "SimpleHTMLFormatter.h" 13 | 14 | using namespace std; 15 | using namespace Lucene; 16 | 17 | int main(int argc, char **argv) { 18 | string indexName = argv[1]; 19 | 20 | Lucene::IndexReaderPtr indexReader; 21 | Lucene::SearcherPtr searcher; 22 | Lucene::AnalyzerPtr analyzer; 23 | Lucene::QueryParserPtr parser; 24 | 25 | Lucene::String dirName(StringUtils::toUnicode(indexName)); 26 | 27 | indexReader = IndexReader::open(FSDirectory::open(dirName), true); 28 | searcher = newLucene(indexReader); 29 | analyzer = newLucene(LuceneVersion::LUCENE_CURRENT); 30 | parser = newLucene(LuceneVersion::LUCENE_CURRENT, L"contents", analyzer); 31 | 32 | string queryStr; 33 | 34 | while (std::getline(cin, queryStr)) { 35 | Lucene::String queryLStr(StringUtils::toUnicode(queryStr)); 36 | 37 | TopScoreDocCollectorPtr collector = TopScoreDocCollector::create(10, false); 38 | 39 | 40 | try { 41 | QueryPtr query = parser->parse(queryLStr); 42 | searcher->search(query, collector); 43 | 44 | Collection hits = collector->topDocs()->scoreDocs; 45 | 46 | for (int32_t i = 0; i < hits.size(); ++i) { 47 | DocumentPtr doc = searcher->doc(hits[i]->doc); 48 | cout << StringUtils::toUTF8(doc->get(L"path")) << endl; 49 | } 50 | } catch (std::exception const &e) { 51 | std::cerr << e.what() << std::endl; 52 | } catch (boost::exception const &e) { 53 | std::cerr << boost::diagnostic_information(e) << std::endl; 54 | } 55 | cout << "END" << std::endl; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zest", 3 | "license": "Private", 4 | "private": true, 5 | "dependencies": { 6 | "escape-html": "^1.0.3", 7 | "escape-regexp": "0.0.1", 8 | "fs-extra": "0.26.4", 9 | "fuzzysearch": "^1.0.3", 10 | "handlebars": "^4.0.5", 11 | "lazy": "^1.0.11", 12 | "leveldown": "^1.4.3", 13 | "levelup": "^1.3.1", 14 | "mkdirp": "^0.5.1", 15 | "parse5": "^2.1.0", 16 | "request": "^2.67.0", 17 | "rimraf": "^2.5.0", 18 | "shell-escape": "^0.2.0", 19 | "split.js": "^1.0.6", 20 | "webtorrent": "^0.72.1" 21 | }, 22 | "devDependencies": { 23 | "electron-packager": "5.2.0", 24 | "electron-rebuild": "^1.1.2", 25 | "grunt": "0.4.5", 26 | "grunt-download-electron": "2.1.2", 27 | "moment": "2.11.1", 28 | "shelljs": "0.5.3", 29 | "winresourcer": "0.9.0" 30 | }, 31 | "optionalDependencies": { 32 | "grunt-appdmg": "0.3.2" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /project.clj: -------------------------------------------------------------------------------- 1 | (defproject zest "0.1.1" 2 | :description "FIXME: write description" 3 | :url "http://example.com/FIXME" 4 | :license {:name "Eclipse Public License" 5 | :url "http://www.eclipse.org/legal/epl-v10.html"} 6 | 7 | :source-paths ["src/cljs"] 8 | 9 | :dependencies [[org.clojure/clojure "1.7.0"] 10 | [org.clojure/clojurescript "1.7.228"] 11 | [org.clojure/core.async "0.2.374"] 12 | [cljsjs/react "0.13.3-1"] 13 | [cljsjs/nodejs-externs "1.0.4-1"] 14 | [reagent "0.5.1"] 15 | [medley "0.7.0"]] 16 | 17 | :plugins [[lein-cljsbuild "1.1.2"]] 18 | 19 | :min-lein-version "2.5.3" 20 | 21 | :cljsbuild {:builds {:app {:source-paths ["src/cljs"] 22 | :compiler {:output-to "app/js/p/app.js" 23 | :output-dir "app/js/p/out" 24 | :asset-path "js/p/out" 25 | :optimizations :none 26 | :pretty-print true 27 | :cache-analysis true}}}} 28 | 29 | :clean-targets ^{:protect false} [:target-path "out" "app/js/p"] 30 | 31 | :figwheel {:css-dirs ["app/css"]} 32 | 33 | :profiles {:dev {:cljsbuild {:builds {:app {:source-paths ["env/dev/cljs"] 34 | :compiler {:source-map true 35 | :main "zest.dev" 36 | :verbose true} 37 | :figwheel {:on-jsload "zest.core/on-figwheel-reload"}}}} 38 | :source-paths ["env/dev/cljs"] 39 | 40 | :dependencies [[figwheel-sidecar "0.5.0-3"]] 41 | 42 | :plugins [[lein-ancient "0.6.8"] 43 | [lein-kibit "0.1.2"] 44 | [lein-cljfmt "0.3.0"] 45 | [lein-figwheel "0.5.0-3"]]} 46 | 47 | :production {:cljsbuild {:builds {:app {:compiler {:optimizations :whitespace 48 | :main "zest.prod" 49 | :parallel-build true 50 | :cache-analysis false 51 | :closure-defines {"goog.DEBUG" false} 52 | :externs ["externs/misc.js"] 53 | :pretty-print false} 54 | :source-paths ["env/prod/cljs"]}}}}} 55 | ) 56 | -------------------------------------------------------------------------------- /scripts/build-windows-exe.nsi: -------------------------------------------------------------------------------- 1 | ;; This script generates the windows .exe file for distribution. 2 | ;; NSIS - http://nsis.sourceforge.net/Main_Page 3 | 4 | ;; HM NIS Edit Wizard helper defines 5 | !define PRODUCT_NAME "zest" 6 | ;; !define PRODUCT_VERSION "0.0" ;; This is auto-defined by the caller in the release script 7 | !define PRODUCT_WEB_SITE "https://zestdocs.org/" 8 | !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\zest.exe" 9 | !define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}" 10 | !define PRODUCT_UNINST_ROOT_KEY "HKLM" 11 | !define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir" 12 | 13 | ;; MUI 1.67 compatible ------ 14 | !include "MUI.nsh" 15 | 16 | ;; MUI Settings 17 | !define MUI_ABORTWARNING 18 | !define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" 19 | !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico" 20 | 21 | ;; Welcome page 22 | !insertmacro MUI_PAGE_WELCOME 23 | 24 | ;; Directory page 25 | !insertmacro MUI_PAGE_DIRECTORY 26 | 27 | ;; Start menu page 28 | var ICONS_GROUP 29 | !define MUI_STARTMENUPAGE_NODISABLE 30 | !define MUI_STARTMENUPAGE_DEFAULTFOLDER "Zest" 31 | !define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}" 32 | !define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}" 33 | !define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}" 34 | !insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP 35 | 36 | ;; Instfiles page 37 | !insertmacro MUI_PAGE_INSTFILES 38 | 39 | ;; Finish page 40 | !define MUI_FINISHPAGE_RUN "$INSTDIR\zest.exe" 41 | !insertmacro MUI_PAGE_FINISH 42 | 43 | ; Uninstaller pages 44 | !insertmacro MUI_UNPAGE_INSTFILES 45 | 46 | ; Language files 47 | !insertmacro MUI_LANGUAGE "English" 48 | 49 | ; Source directory 50 | ; (auto-defined by the caller in the release script) 51 | ;; !define OUTFILE 52 | ;; !define RELEASE_DIR 53 | 54 | ; MUI end ------ 55 | 56 | Name "${PRODUCT_NAME} ${PRODUCT_VERSION}" 57 | OutFile "${OUTFILE}" 58 | InstallDir "$PROGRAMFILES\Zest" 59 | InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" "" 60 | ShowInstDetails show 61 | ShowUnInstDetails show 62 | 63 | Section "MainSection" SEC01 64 | SetOutPath "$INSTDIR" 65 | SetOverwrite ifnewer 66 | File /r "${RELEASE_DIR}\*" 67 | 68 | ;; Shortcuts 69 | !insertmacro MUI_STARTMENU_WRITE_BEGIN Application 70 | CreateDirectory "$SMPROGRAMS\$ICONS_GROUP" 71 | CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\zest.lnk" "$INSTDIR\zest.exe" 72 | CreateShortCut "$DESKTOP\zest.lnk" "$INSTDIR\zest.exe" 73 | !insertmacro MUI_STARTMENU_WRITE_END 74 | SectionEnd 75 | 76 | Section -AdditionalIcons 77 | SetOutPath $INSTDIR 78 | !insertmacro MUI_STARTMENU_WRITE_BEGIN Application 79 | WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}" 80 | CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url" 81 | CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe" 82 | !insertmacro MUI_STARTMENU_WRITE_END 83 | SectionEnd 84 | 85 | Section -Post 86 | WriteUninstaller "$INSTDIR\uninst.exe" 87 | WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\zest.exe" 88 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)" 89 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe" 90 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\zest.exe" 91 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}" 92 | WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}" 93 | SectionEnd 94 | 95 | 96 | Function un.onUninstSuccess 97 | HideWindow 98 | MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer." 99 | FunctionEnd 100 | 101 | Function un.onInit 102 | MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2 103 | Abort 104 | FunctionEnd 105 | 106 | Section Uninstall 107 | !insertmacro MUI_STARTMENU_GETFOLDER "Application" $ICONS_GROUP 108 | 109 | Delete "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" 110 | Delete "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" 111 | Delete "$DESKTOP\zest.lnk" 112 | Delete "$SMPROGRAMS\$ICONS_GROUP\zest.lnk" 113 | 114 | RMDir "$SMPROGRAMS\$ICONS_GROUP" 115 | 116 | RMDir /r "$INSTDIR" 117 | 118 | DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" 119 | DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}" 120 | SetAutoClose true 121 | SectionEnd 122 | -------------------------------------------------------------------------------- /scripts/build_app.bat: -------------------------------------------------------------------------------- 1 | call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64 2 | 3 | call lein self-install 4 | call grunt cljsbuild-prod 5 | call grunt prepare-release 6 | 7 | mkdir builds\app\node_modules\sqlite3\lib\binding\node-v47-win32-x64 8 | copy node_modules\sqlite3\lib\binding\node-v47-win32-x64\node_sqlite3.node builds\app\node_modules\sqlite3\lib\binding\node-v47-win32-x64\node_sqlite3.node 9 | copy node_modules\sqlite3\lib\*.js builds\app\node_modules\sqlite3\lib\ 10 | copy node_modules\sqlite3\package.json builds\app\node_modules\sqlite3 11 | copy node_modules\sqlite3\sqlite3.js builds\app\node_modules\sqlite3 12 | cd builds\app\node_modules\sqlite3 13 | call npm install 14 | cd c:\zest_build 15 | 16 | mkdir builds\app\node_modules\leveldown\build\Release 17 | copy node_modules\leveldown\build\Release\leveldown.node builds\app\node_modules\leveldown\build\Release 18 | copy node_modules\leveldown\*.js builds\app\node_modules\leveldown 19 | 20 | copy node_modules\nodelucene.node builds\app\node_modules 21 | 22 | call grunt prepare-win 23 | 24 | cd builds\zest-v* 25 | mkdir zest-win32-x64\resources\sqlite_score 26 | 27 | copy ..\..\sqlite_score\zest_score.sqlext zest-win32-x64\resources\sqlite_score 28 | copy ..\..\sogrep-src\Release\*.exe zest-win32-x64\resources 29 | copy ..\..\nodelucene\Release\searcher.exe zest-win32-x64\resources 30 | copy "..\..\LucenePlusPlus\build\src\core\Release\lucene++.dll" zest-win32-x64 31 | copy "..\..\LucenePlusPlus\build\src\contrib\Release\lucene++-contrib.dll" zest-win32-x64 32 | copy ..\..\xercesc.redist.3.1.1\build\native\bin\x64\v110\Release\xerces-c_3_1.dll zest-win32-x64 33 | copy ..\..\libarchive\zest_build\bin\Release\archive.dll zest-win32-x64 34 | copy ..\..\bzip2.v120.1.0.6.2\build\native\bin\x64\Release\bzip2.dll zest-win32-x64 35 | 36 | copy "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\redist\x64\Microsoft.VC110.CRT\msvcr110.dll" zest-win32-x64 37 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_filesystem-vc120-mt-1_59.dll zest-win32-x64 38 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_regex-vc120-mt-1_59.dll zest-win32-x64 39 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_system-vc120-mt-1_59.dll zest-win32-x64 40 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_thread-vc120-mt-1_59.dll zest-win32-x64 41 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_chrono-vc120-mt-1_59.dll zest-win32-x64 42 | copy C:\Libraries\boost_1_59_0\stage\lib\boost_date_time-vc120-mt-1_59.dll zest-win32-x64 43 | 44 | cd ..\.. 45 | 46 | call choco install nsis.install -pre -y 47 | set PATH=C:\Program Files (x86)\NSIS\Bin;%PATH% 48 | call grunt release-win 49 | -------------------------------------------------------------------------------- /scripts/build_circle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ELECTRON_VERSION=$(grep 'electron_version = ' Gruntfile.js | cut -d '"' -f 2) 4 | 5 | cd nodelucene 6 | PKG_CONFIG_PATH=$HOME/installprefix/lib/pkgconfig cmake . 7 | make 8 | 9 | cd ../sogrep-src 10 | PKG_CONFIG_PATH=$HOME/installprefix/lib/pkgconfig cmake . 11 | make 12 | 13 | cd .. 14 | npm install node-gyp 15 | npm install --no-optional 16 | 17 | # rebuild nodelucene: 18 | HOME=~/.electron-gyp ./node_modules/.bin/node-gyp rebuild --target=$ELECTRON_VERSION --arch=x64 --dist-url=https://atom.io/download/atom-shell 19 | # rebuild leveldown: 20 | cd node_modules/leveldown 21 | HOME=~/.electron-gyp ../.bin/node-gyp rebuild --target=$ELECTRON_VERSION --arch=x64 --dist-url=https://atom.io/download/atom-shell 22 | cd ../.. 23 | # rebuild node_sqlite3: 24 | npm install $HOME/node-sqlite3 25 | cd node_modules/sqlite3 26 | HOME=~/.electron-gyp ../.bin/node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-linux-x64 27 | HOME=~/.electron-gyp ../.bin/node-gyp rebuild --target=$ELECTRON_VERSION --arch=x64 --target_platform=linux --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-linux-x64 28 | cd ../.. 29 | cp node_modules/sqlite3/build/Release/node_sqlite3.node node_modules/sqlite3/lib/binding/node-v47-linux-x64 30 | # build zest_score.sqlext: 31 | gcc -shared -fPIC -I$HOME/node-sqlite3/deps/sqlite-autoconf-3090100 -o zest_score.sqlext sqlite_score/score.c 32 | 33 | npm install grunt-cli bower 34 | ./node_modules/.bin/grunt setup 35 | ./node_modules/.bin/bower install 36 | 37 | ./node_modules/.bin/grunt cljsbuild-prod 38 | ./node_modules/.bin/grunt prepare-release 39 | cp build/Release/nodelucene.node builds/app/node_modules 40 | cp -r node_modules/{sqlite3,leveldown} builds/app/node_modules 41 | ./node_modules/.bin/grunt release-linux 42 | 43 | cp --no-dereference $HOME/installprefix/lib/lib*.so* builds/zest-v*/zest-linux-x64/resources 44 | cp --no-dereference $HOME/installprefix/lib/x86_64-linux-gnu/lib*.so* builds/zest-v*/zest-linux-x64/resources 45 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libboost*.so* builds/zest-v*/zest-linux-x64/resources 46 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libleveldb*.so* builds/zest-v*/zest-linux-x64/resources 47 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libxerces*.so* builds/zest-v*/zest-linux-x64/resources 48 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libicuuc*.so* builds/zest-v*/zest-linux-x64/resources 49 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libicui18n*.so* builds/zest-v*/zest-linux-x64/resources 50 | cp --no-dereference /usr/lib/x86_64-linux-gnu/libicudata*.so* builds/zest-v*/zest-linux-x64/resources 51 | cp --no-dereference /usr/lib/libsnappy*.so* builds/zest-v*/zest-linux-x64/resources 52 | cp sogrep-src/{extractor,sogrep} builds/zest-v*/zest-linux-x64/resources 53 | cp nodelucene/searcher builds/zest-v*/zest-linux-x64/resources 54 | cd builds/zest-v* 55 | mkdir zest-linux-x64/resources/sqlite_score 56 | cd ../.. 57 | cp zest_score.sqlext builds/zest-v*/zest-linux-x64/resources/sqlite_score 58 | 59 | cd builds/zest-v*/zest-linux-x64 60 | ln -s resources/liblucene++* . 61 | ln -s resources/libicu* . 62 | cd .. 63 | mv zest-linux-x64 `basename $PWD` 64 | tar -czvf `basename $PWD`-linux-x64.tar.gz `basename $PWD` 65 | 66 | mv `basename $PWD`-linux-x64.tar.gz $CIRCLE_ARTIFACTS -------------------------------------------------------------------------------- /scripts/build_circle_deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd $HOME 4 | mkdir -p $HOME/installprefix/lib/pkgconfig 5 | 6 | if [ ! -d $HOME/installprefix/include/rapidjson ]; then 7 | git clone https://github.com/miloyip/rapidjson.git 8 | cd rapidjson 9 | git checkout v1.0.2 10 | mkdir -p $HOME/installprefix/include 11 | cp -r include/rapidjson $HOME/installprefix/include 12 | cd .. 13 | fi 14 | 15 | if [ ! -d "$HOME/LucenePlusPlus" ]; then 16 | git clone https://github.com/jkozera/LucenePlusPlus.git 17 | cd LucenePlusPlus 18 | mkdir build 19 | cd build 20 | cmake .. -DCMAKE_INSTALL_PREFIX:PATH=$HOME/installprefix 21 | make install 22 | else 23 | cd LucenePlusPlus/build 24 | fi 25 | make install 26 | cp liblucene++*.pc $HOME/installprefix/lib/pkgconfig 27 | cd ../.. 28 | 29 | if [ ! -d "$HOME/libarchive" ]; then 30 | git clone https://github.com/libarchive/libarchive.git 31 | cd libarchive 32 | git checkout 884f82a93ee5eb932b1e0fb74b6893708a43dc6d 33 | mkdir -p zest_build/installprefix 34 | cd zest_build 35 | cmake .. -DENABLE_OPENSSL=OFF -DCMAKE_INSTALL_PREFIX:PATH=$HOME/installprefix 36 | else 37 | cd libarchive/zest_build 38 | fi 39 | make install 40 | cd ../.. 41 | 42 | if [ ! -d "$HOME/node-sqlite3" ]; then 43 | git clone https://github.com/jkozera/node-sqlite3.git 44 | cd node-sqlite3 45 | npm install 46 | cd deps 47 | tar -zxvf sqlite-autoconf-3090100.tar.gz 48 | cd ../.. 49 | fi 50 | 51 | if [ ! -d "$HOME/patchelf-0.9" ]; then 52 | wget https://github.com/NixOS/patchelf/archive/0.9.tar.gz 53 | tar -zxvf 0.9.tar.gz 54 | cd patchelf-0.9 55 | ./bootstrap.sh 56 | ./configure 57 | make 58 | cd .. 59 | fi 60 | 61 | ~/patchelf-0.9/src/patchelf --set-rpath '$ORIGIN/resources:$ORIGIN' installprefix/lib/x86_64-linux-gnu/liblucene++.so 62 | ~/patchelf-0.9/src/patchelf --set-rpath '$ORIGIN/resources:$ORIGIN' installprefix/lib/x86_64-linux-gnu/liblucene++-contrib.so -------------------------------------------------------------------------------- /scripts/build_deps.bat: -------------------------------------------------------------------------------- 1 | call "%VS120COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64 2 | 3 | 4 | REM ## 1. zlib 5 | REM ########## 6 | c:\msys64\usr\bin\curl --silent -O http://zlib.net/zlib-1.2.8.tar.gz 7 | c:\msys64\usr\bin\pacman --noconfirm -S tar gzip unzip wget 8 | c:\msys64\usr\bin\gzip -d zlib-1.2.8.tar.gz 9 | c:\msys64\usr\bin\tar -xvf zlib-1.2.8.tar 10 | 11 | 12 | REM ## 2. 64bit Boost 13 | REM ################# 14 | cd \Libraries\boost_1_59_0 15 | 16 | call bootstrap 17 | b2 --prefix=c:\Libraries\boost_1_59_0 --with-filesystem --with-regex --with-system --with-thread --with-chrono --with-date_time address-model=64 link=shared variant=release runtime-link=shared 18 | b2 --prefix=c:\Libraries\boost_1_59_0 -sZLIB_SOURCE=c:\zest_build\zlib-1.2.8 --with-iostreams address-model=64 link=static variant=release runtime-link=shared 19 | 20 | set BOOST_ROOT=C:\Libraries\boost_1_59_0 21 | set BOOST_LIBRARYDIR=C:\Libraries\boost_1_59_0\stage\lib 22 | 23 | REM ## 3. LucenePlusPlus 24 | REM #################### 25 | cd \zest_build 26 | 27 | if not exist "LucenePlusPlus\build\src\core\Release\lucene++.dll" goto build_lucene 28 | if not exist "LucenePlusPlus\build\src\contrib\Release\lucene++-contrib.dll" goto build_lucene 29 | goto skip_lucene 30 | 31 | :build_lucene 32 | git clone https://github.com/jkozera/LucenePlusPlus.git 33 | copy /y LucenePlusPlusCMakeLists.txt.appveyor LucenePlusPlus\CMakeLists.txt 34 | cd LucenePlusPlus 35 | mkdir build 36 | cd build 37 | 38 | cmake .. -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_CXX_FLAGS="/D NOMINMAX /D LPP_HAVE_DLL" 39 | 40 | msbuild src\core\lucene++.vcxproj /p:Configuration=Release 41 | msbuild src\contrib\lucene++-contrib.vcxproj /p:Configuration=Release 42 | cd ..\.. 43 | 44 | :skip_lucene 45 | 46 | mkdir bzip2_prefix\include 47 | mkdir bzip2_prefix\lib 48 | 49 | copy bzip2.v120.1.0.6.2\build\native\include\bzlib.h bzip2_prefix\include 50 | copy bzip2.v120.1.0.6.2\build\native\lib\x64\Release\libbz2.lib bzip2_prefix\lib 51 | 52 | if not exist libarchive\zest_build\bin\Release\archive.dll goto build_libarchive 53 | goto skip_libarchive 54 | 55 | :build_libarchive 56 | git clone https://github.com/libarchive/libarchive.git 57 | cd libarchive 58 | git checkout 884f82a93ee5eb932b1e0fb74b6893708a43dc6d 59 | mkdir zest_build 60 | cd zest_build 61 | cmake .. -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_PREFIX_PATH=c:/zest_build/bzip2_prefix -DBZIP2_LIBRARIES=c:/zest_build/bzip2_prefix/lib/libbz2.lib -DENABLE_OPENSSL=OFF 62 | msbuild libarchive\archive.vcxproj /p:Configuration=Release 63 | cd ..\.. 64 | 65 | :skip_libarchive 66 | 67 | copy /y LevelDB.1.16.0.5\lib\native\src\util\crc32c.cc LevelDB.1.16.0.5\lib\native\src\port\win\crc32c_win.cc 68 | cd sogrep-src 69 | copy /y CMakeLists.txt.appveyor CMakeLists.txt 70 | cmake . -DCMAKE_GENERATOR_PLATFORM=x64 -DCMAKE_CXX_FLAGS="/D LEVELDB_PLATFORM_WINDOWS" 71 | msbuild sogrep.vcxproj /p:Configuration=Release 72 | msbuild extractor.vcxproj /p:Configuration=Release 73 | 74 | cd .. 75 | c:\msys64\usr\bin\wget --quiet https://github.com/atom/electron/releases/download/v0.36.7/electron-v0.36.9-win32-x64.zip 76 | mkdir electron 77 | cd electron 78 | c:\msys64\usr\bin\unzip ..\electron-v0.36.9-win32-x64.zip 79 | 80 | cd ..\nodelucene 81 | copy /y CMakeLists.txt.appveyor CMakeLists.txt 82 | cmake . -DCMAKE_GENERATOR_PLATFORM=x64 83 | msbuild searcher.vcxproj /p:Configuration=Release 84 | 85 | cd .. 86 | copy /y binding.gyp.appveyor binding.gyp 87 | set GYP_MSVS_VERSION=2013 88 | call npm install --no-optional 89 | call npm install -g node-gyp 90 | 91 | set USERPROFILE=%USERPROFILE%\.electron-gyp 92 | REM ## rebuild leveldown: 93 | cd node_modules\leveldown 94 | call node-gyp rebuild --target=0.36.9 --arch=x64 --dist-url=https://atom.io/download/atom-shell 95 | REM ## rebuild nodelucene: 96 | cd ..\.. 97 | call node-gyp rebuild --target=0.36.9 --arch=x64 --dist-url=https://atom.io/download/atom-shell 98 | 99 | copy build\Release\nodelucene.node node_modules 100 | 101 | git clone https://github.com/jkozera/node-sqlite3.git 102 | 103 | cd node-sqlite3\deps 104 | copy sqlite-autoconf-3090100.tar.gz sqlite-autoconf-3090100.2.tar.gz 105 | c:\msys64\usr\bin\gzip -d sqlite-autoconf-3090100.2.tar.gz 106 | c:\msys64\usr\bin\tar -xvf sqlite-autoconf-3090100.2.tar 107 | cd c:\zest_build\sqlite_score 108 | cl score.c /I ..\node-sqlite3\deps\sqlite-autoconf-3090100 -link -dll -out:zest_score.sqlext 109 | 110 | cd .. 111 | call npm install -g grunt-cli 112 | call npm install -g bower 113 | cd node-sqlite3 114 | call npm install 115 | cd .. 116 | call npm install .\node-sqlite3 117 | 118 | cd node_modules\sqlite3 119 | call node-gyp configure --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64 120 | call node-gyp rebuild --target=0.36.9 --arch=x64 --target_platform=win32 --dist-url=https://atom.io/download/atom-shell --module_name=node_sqlite3 --module_path=../lib/binding/node-v47-win32-x64 121 | cd ..\.. 122 | copy /y node_modules\sqlite3\build\Release\node_sqlite3.node node_modules\sqlite3\lib\binding\node-v47-win32-x64 123 | 124 | call grunt setup 125 | call bower install 126 | 127 | c:\msys64\usr\bin\wget --quiet https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein.bat 128 | -------------------------------------------------------------------------------- /scripts/dmg/TestBkg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/scripts/dmg/TestBkg.png -------------------------------------------------------------------------------- /scripts/dmg/TestBkg@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zestdocs/zest/aca730cbca8b82184dab0e44abc558f7a2512249/scripts/dmg/TestBkg@2x.png -------------------------------------------------------------------------------- /scripts/setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | pushd "%~dp0\.." 4 | 5 | echo. & echo Installing node dependencies... 6 | call npm install --no-optional 7 | 8 | echo. & echo Installing grunt & bower... 9 | call npm install -g grunt-cli 10 | call npm install -g bower 11 | 12 | call grunt setup 13 | 14 | echo. & echo setup complete. 15 | 16 | popd 17 | -------------------------------------------------------------------------------- /scripts/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # exit on errors 4 | set -e 5 | 6 | cd "`dirname $0`/.." 7 | 8 | echo; echo "Installing node dependencies..." 9 | if [[ "$OSTYPE" == "darwin"* ]]; then 10 | npm install 11 | else 12 | # "grunt-appdmg" is a mac-only dependency that will fail to build on linux. 13 | # So we are including it as an optionalDependency in package.json 14 | # and preventing its installation with npm's --no-optional flag. 15 | npm install --no-optional 16 | fi 17 | 18 | ELECTRON_VERSION=$(grep 'electron_version = ' Gruntfile.js | cut -d '"' -f 2) 19 | HOME=~/.electron-gyp node-gyp rebuild --target=$ELECTRON_VERSION --arch=x64 --dist-url=https://atom.io/download/atom-shell 20 | pushd node_modules/leveldown 21 | HOME=~/.electron-gyp node-gyp rebuild --target=$ELECTRON_VERSION --arch=x64 --dist-url=https://atom.io/download/atom-shell 22 | popd 23 | 24 | echo; echo "Installing grunt and bower..." 25 | 26 | npm install -g grunt-cli bower 27 | 28 | grunt setup 29 | 30 | echo; echo "Setup complete." 31 | -------------------------------------------------------------------------------- /sogrep-src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 2.8.12) 2 | project(sogrep) 3 | 4 | # from https://cmake.org/pipermail/cmake/2008-January/019321.html 5 | MACRO (APPEND_CMAKE_INSTALL_RPATH RPATH_DIRS) 6 | IF (NOT ${ARGC} EQUAL 1) 7 | MESSAGE(SEND_ERROR "APPEND_CMAKE_INSTALL_RPATH takes 1 argument") 8 | ENDIF (NOT ${ARGC} EQUAL 1) 9 | FOREACH ( RPATH_DIR ${RPATH_DIRS} ) 10 | IF ( NOT ${RPATH_DIR} STREQUAL "" ) 11 | FILE( TO_CMAKE_PATH ${RPATH_DIR} RPATH_DIR ) 12 | STRING( SUBSTRING ${RPATH_DIR} 0 1 RPATH_FIRST_CHAR ) 13 | IF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 14 | # relative path; CMake handling for these is unclear, 15 | # add them directly to the linker line. Add both $ORIGIN 16 | # and $$ORIGIN to ensure correct behavior for exes and 17 | # shared libraries. 18 | SET ( RPATH_DIR "$ORIGIN/${RPATH_DIR}:$$ORIGIN/${RPATH_DIR}" ) 19 | SET ( CMAKE_EXE_LINKER_FLAGS 20 | "${CMAKE_EXE_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" ) 21 | SET ( CMAKE_SHARED_LINKER_FLAGS 22 | "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-rpath,'${RPATH_DIR}'" ) 23 | ELSE ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 24 | # absolute path 25 | SET ( CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH}:${RPATH_DIR}" ) 26 | ENDIF ( NOT ${RPATH_FIRST_CHAR} STREQUAL "/" ) 27 | ENDIF ( NOT ${RPATH_DIR} STREQUAL "" ) 28 | ENDFOREACH ( RPATH_DIR ) 29 | ENDMACRO ( APPEND_CMAKE_INSTALL_RPATH ) 30 | 31 | APPEND_CMAKE_INSTALL_RPATH(".") 32 | 33 | find_package(PkgConfig) 34 | pkg_search_module(XERCES REQUIRED xerces-c) 35 | pkg_search_module(LIBARCHIVE REQUIRED libarchive) 36 | 37 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -L${XERCES_LIBRARY_DIRS} -L${LIBARCHIVE_LIBRARY_DIRS}") 38 | 39 | link_directories( 40 | "/usr/local/lib" 41 | ${LIBARCHIVE_LIBRARY_DIRS} 42 | ${XERCES_LIBRARY_DIRS} 43 | ) 44 | add_executable(sogrep main.cpp) 45 | add_executable(extractor extractor.cpp) 46 | target_link_libraries( 47 | sogrep 48 | leveldb 49 | ${XERCES_LIBRARIES} 50 | ) 51 | target_include_directories( 52 | sogrep 53 | PUBLIC 54 | "/usr/local/include" 55 | ${XERCES_INCLUDE_DIRS} 56 | # For rapidjson from Circle CI: 57 | "/home/ubuntu/installprefix/include" 58 | ) 59 | target_compile_options( 60 | sogrep 61 | PUBLIC 62 | ${XERCES_CFLAGS_OTHER} 63 | ) 64 | 65 | target_link_libraries( 66 | extractor 67 | ${LIBARCHIVE_LIBRARIES} 68 | ) 69 | target_include_directories( 70 | extractor 71 | PUBLIC 72 | "/usr/local/include" 73 | ${LIBARCHIVE_INCLUDE_DIRS} 74 | ) 75 | target_compile_options( 76 | extractor 77 | PUBLIC 78 | ${LIBARCHIVE_CFLAGS_OTHER} 79 | ) 80 | -------------------------------------------------------------------------------- /sogrep-src/CMakeLists.txt.appveyor: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.3) 2 | project(sogrep) 3 | 4 | find_package(PkgConfig) 5 | 6 | link_directories( 7 | "/usr/local/lib" 8 | "C:\\zest_build\\libarchive\\zest_build\\libarchive\\Release" 9 | "C:\\zest_build\\xercesc.3.1.1\\build\\native\\lib\\x64\\v110\\Release" 10 | ) 11 | add_executable(sogrep 12 | main.cpp 13 | "c:/zest_build/LevelDB.1.16.0.5/lib/native/src/leveldb-single-file.cpp" 14 | ) 15 | add_executable(extractor extractor.cpp) 16 | target_link_libraries( 17 | sogrep 18 | "xerces-c_3.lib" 19 | "Shlwapi.lib" 20 | ) 21 | target_include_directories( 22 | sogrep 23 | PUBLIC 24 | "C:\\zest_build\\xercesc.3.1.1\\build\\native\\include" 25 | "C:\\zest_build\\rapidjson.1.0.2\\build\\native\\include" 26 | "C:\\zest_build\\LevelDB.1.16.0.5\\lib\\native\\include" 27 | "C:\\zest_build\\LevelDB.1.16.0.5\\lib\\native\\src" 28 | "C:\\zest_build\\LevelDB.1.16.0.5\\lib\\native\\src\\port\\win" 29 | ) 30 | target_compile_options( 31 | sogrep 32 | PUBLIC 33 | ) 34 | 35 | target_link_libraries( 36 | extractor 37 | "C:\\zest_build\\libarchive\\zest_build\\libarchive\\Release\\archive.lib" 38 | ) 39 | target_include_directories( 40 | extractor 41 | PUBLIC 42 | "C:\\zest_build\\libarchive\\libarchive" 43 | ) 44 | target_compile_options( 45 | extractor 46 | PUBLIC 47 | ) 48 | -------------------------------------------------------------------------------- /sogrep-src/extractor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include 8 | #define write _write 9 | #endif 10 | 11 | void print_size(char* filename) { 12 | archive *a = archive_read_new(); 13 | archive_read_support_filter_bzip2(a); 14 | archive_read_support_format_7zip(a); 15 | 16 | archive_read_open_filename(a, filename, 10240); 17 | 18 | archive_entry *entry; 19 | archive_read_next_header(a, &entry); 20 | 21 | std::cout << archive_entry_size(entry); 22 | 23 | archive_read_free(a); 24 | } 25 | 26 | void extract(char* filename) { 27 | archive *a = archive_read_new(); 28 | archive_read_support_filter_bzip2(a); 29 | archive_read_support_format_7zip(a); 30 | 31 | archive_read_open_filename(a, filename, 10240); 32 | 33 | archive_entry *entry; 34 | archive_read_next_header(a, &entry); 35 | archive_read_data_into_fd(a, 1); 36 | 37 | archive_read_free(a); 38 | } 39 | 40 | int main(int argc, char** argv) { 41 | if (argc == 5 && strcmp(argv[4], "sizes") == 0) { 42 | print_size(argv[1]); 43 | std::cout << " "; 44 | print_size(argv[2]); 45 | std::cout << " "; 46 | print_size(argv[3]); 47 | std::cout << std::endl; 48 | } else { 49 | extract(argv[1]); // Path to Posts.xml 7z file 50 | write(1, "\0", 1); // null separator, as expected in main.cpp 51 | extract(argv[2]); // Path to Comments.xml 7z file 52 | write(1, "\0", 1); // null separator, as expected in main.cpp 53 | extract(argv[3]); // Path to Users.xml 7z file 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sogrep-src/grep_python.py: -------------------------------------------------------------------------------- 1 | import json 2 | import plyvel 3 | import sys 4 | import time 5 | import xml.sax 6 | import xml.sax.handler 7 | 8 | 9 | def a2d(attrs): 10 | return {n: attrs.getValue(n) 11 | for n in attrs.getNames()} 12 | 13 | 14 | class MyHandler(xml.sax.handler.ContentHandler): 15 | 16 | def __init__(self): 17 | self.pyids = set() 18 | self.posts = {} 19 | self.id2obj = {} 20 | self.comments = False 21 | # self.outfile = open('json.json', 'w') 22 | 23 | def startElement(self, name, attrs): 24 | if name == 'row' and not self.comments: 25 | rowid = attrs.getValue('Id') 26 | ispy = False 27 | 28 | try: 29 | if '' in attrs.getValue('Tags'): 30 | ispy = True 31 | except KeyError: 32 | try: 33 | ispy = attrs.getValue('ParentId') in self.pyids 34 | except KeyError: 35 | if attrs.getValue('PostTypeId') not in ['3', '4', '5']: # Tag Wiki 36 | print(json.dumps(a2d(attrs))) 37 | 38 | if ispy: 39 | self.pyids.add(rowid) 40 | 41 | obj = a2d(attrs) 42 | obj['comments'] = [] 43 | self.id2obj[obj['Id']] = obj 44 | 45 | if ispy: 46 | if obj['PostTypeId'] == '1': 47 | self.posts[obj['Id']] = obj 48 | self.posts[obj['Id']]['children'] = [] 49 | else: 50 | self.posts[obj['ParentId']]['children'].append( 51 | obj 52 | ) 53 | 54 | elif (name == 'row' and self.comments and 55 | attrs.getValue('PostId') in self.id2obj): 56 | obj = a2d(attrs) 57 | self.id2obj[obj['PostId']]['comments'].append(obj) 58 | elif name != 'row': 59 | print(name) 60 | 61 | handler = MyHandler() 62 | parser = xml.sax.make_parser() 63 | parser.setContentHandler(handler) 64 | chunk = sys.stdin.read(10000) 65 | chunk1 = None 66 | done = 0 67 | t0 = time.time() 68 | while len(chunk) != 0: 69 | if '\x00' in chunk: 70 | chunk, chunk1 = chunk.split('\x00') 71 | parser.feed(chunk) 72 | done += 10000 73 | if done % (10000*1000) == 0: 74 | elapsed = time.time() - t0 75 | ALL = 9601970627 + 30613095889. 76 | print(done, elapsed*(1/(done/ALL) - 1)) 77 | print(1/(done/ALL)) 78 | if chunk1: 79 | chunk = chunk1 + sys.stdin.read(10240) 80 | parser = xml.sax.make_parser() 81 | parser.setContentHandler(handler) 82 | handler.comments = True 83 | chunk1 = None 84 | else: 85 | chunk = sys.stdin.read(10240) 86 | 87 | 88 | """db = plyvel.DB('testdb', create_if_missing=True) 89 | db.put(b'count', bytes(str(len(handler.posts)), 'utf-8')) 90 | for k in handler.posts: 91 | db.put(bytes(k, 'utf-8'), bytes(json.dumps(handler.posts[k]), 'utf-8')) 92 | 93 | db.close()""" 94 | 95 | #xml.sax.parse(sys.stdin, handler) 96 | -------------------------------------------------------------------------------- /sogrep-src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifndef WIN32 10 | #include 11 | #endif 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include 22 | 23 | using namespace rapidjson; 24 | using namespace std; 25 | using namespace xercesc; 26 | 27 | vector tagNames; 28 | leveldb::DB* db; 29 | 30 | class ZeroSeparatedBinFileInputStream : public BinFileInputStream { 31 | 32 | public: 33 | virtual XMLSize_t readBytes(XMLByte *const toFill, const XMLSize_t maxToRead) override; 34 | 35 | ZeroSeparatedBinFileInputStream ( 36 | const FileHandle toUse 37 | , MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager 38 | ) : BinFileInputStream(toUse, manager) { } 39 | 40 | static void next() { 41 | doNext = true; 42 | } 43 | 44 | private: 45 | static XMLByte * buf; 46 | static bool doNext; 47 | static XMLSize_t bufLen; 48 | static XMLSize_t done, prevStatus; 49 | static time_t t0; 50 | 51 | // ----------------------------------------------------------------------- 52 | // Unimplemented constructors and operators 53 | // ----------------------------------------------------------------------- 54 | ZeroSeparatedBinFileInputStream(const ZeroSeparatedBinFileInputStream&) : BinFileInputStream("") { }; 55 | ZeroSeparatedBinFileInputStream& operator=(const ZeroSeparatedBinFileInputStream&); 56 | 57 | }; 58 | 59 | bool ZeroSeparatedBinFileInputStream::doNext = false; 60 | XMLSize_t ZeroSeparatedBinFileInputStream::bufLen = 0; 61 | XMLSize_t ZeroSeparatedBinFileInputStream::done = 0; 62 | XMLSize_t ZeroSeparatedBinFileInputStream::prevStatus = 0; 63 | XMLByte * ZeroSeparatedBinFileInputStream::buf = nullptr; 64 | time_t ZeroSeparatedBinFileInputStream::t0 = time(nullptr); 65 | 66 | XMLSize_t ZeroSeparatedBinFileInputStream::readBytes(XMLByte *const toFill, const XMLSize_t maxToRead) { 67 | XMLSize_t ret; 68 | if (buf != nullptr && doNext) { 69 | if (maxToRead <= bufLen) { 70 | copy(buf, buf + maxToRead, toFill); 71 | buf += maxToRead; 72 | done += maxToRead; 73 | bufLen -= maxToRead; 74 | return maxToRead; 75 | } else { 76 | copy(buf, buf + bufLen, toFill); 77 | #ifdef _WIN32 78 | ret = bufLen + BinFileInputStream::readBytes(toFill + bufLen, maxToRead - bufLen); 79 | #else 80 | ret = bufLen + read(0, toFill + bufLen, maxToRead - bufLen); 81 | #endif 82 | bufLen = 0; 83 | delete[] buf; 84 | buf = nullptr; 85 | doNext = false; 86 | } 87 | } else if (buf != nullptr && !doNext) { 88 | return 0; 89 | } else { 90 | #ifdef _WIN32 91 | XMLSize_t all = BinFileInputStream::readBytes(toFill, maxToRead); 92 | #else 93 | XMLSize_t all = read(0, toFill, maxToRead); 94 | #endif 95 | XMLByte * cur = toFill; 96 | while ((cur - toFill < all) && *cur != 0) ++cur; 97 | if (cur - toFill < all) { 98 | ret = (cur - toFill); 99 | bufLen = toFill + all - cur - 1; 100 | buf = new XMLByte[bufLen]; 101 | copy(cur + 1, toFill + all, buf); 102 | } else { 103 | ret = all; 104 | } 105 | } 106 | done += ret; 107 | if (done - prevStatus >= 10000*1000) { 108 | time_t dt = time(nullptr) - t0; 109 | std::cout << done << std::endl; 110 | prevStatus = done; 111 | } 112 | return ret; 113 | } 114 | 115 | 116 | class ZeroPaddedStdInInputSource : public InputSource { 117 | virtual BinInputStream *makeStream() const override; 118 | 119 | public: 120 | ZeroPaddedStdInInputSource(MemoryManager* const manager = XMLPlatformUtils::fgMemoryManager) 121 | : InputSource("stdin", manager) { } 122 | ~ZeroPaddedStdInInputSource() { } 123 | }; 124 | 125 | BinInputStream *ZeroPaddedStdInInputSource::makeStream() const { 126 | BinFileInputStream* retStream = new (getMemoryManager()) ZeroSeparatedBinFileInputStream( 127 | XMLPlatformUtils::openStdInHandle(getMemoryManager()) 128 | ); 129 | 130 | if (!retStream->getIsOpen()) { 131 | delete retStream; 132 | return 0; 133 | } 134 | 135 | return retStream; 136 | } 137 | 138 | inline const string ch2str(const XMLCh* c) { 139 | char* tmp = XMLString::transcode(c); 140 | string ret = string(tmp); 141 | XMLString::release(&tmp); 142 | return ret; 143 | } 144 | 145 | class MySAXHandler : public HandlerBase { 146 | 147 | 148 | bool comments = false; 149 | bool users = false; 150 | 151 | map commentCounts; 152 | map answerCounts; 153 | 154 | public: 155 | void setComments() { comments = true; } 156 | void setUsers() { users = true; } 157 | 158 | const std::string jsonize(AttributeList &attrs) { 159 | StringBuffer s; 160 | Writer w(s); 161 | 162 | w.StartObject(); 163 | for (int i = 0; i < attrs.getLength(); ++i) { 164 | const XMLCh* name = attrs.getName(i); 165 | char *tmpName = XMLString::transcode(name), 166 | *tmpValue = XMLString::transcode(attrs.getValue(name)); 167 | w.String(tmpName); 168 | w.String(tmpValue); 169 | XMLString::release(&tmpName); 170 | XMLString::release(&tmpValue); 171 | } 172 | w.EndObject(); 173 | 174 | return s.GetString(); 175 | } 176 | 177 | void startElement(const XMLCh* const, AttributeList& attrs) { 178 | if (attrs.getValue("Id") != nullptr) { 179 | if (users) { 180 | const string UserId = ch2str(attrs.getValue("Id")); 181 | db->Put( 182 | leveldb::WriteOptions(), 183 | "u_"+UserId, 184 | jsonize(attrs) 185 | ); 186 | } else if (comments) { 187 | const string PostId = ch2str(attrs.getValue("PostId")); 188 | map::iterator match = commentCounts.find(PostId); 189 | if (match != commentCounts.end()) { 190 | db->Put( 191 | leveldb::WriteOptions(), 192 | "c_"+PostId+"_"+std::to_string(match->second), 193 | jsonize(attrs) 194 | ); 195 | commentCounts[PostId] += 1; 196 | } 197 | } else { 198 | const XMLCh* tags = attrs.getValue("Tags"); 199 | 200 | if (tags == nullptr) { 201 | const XMLCh* parentId = attrs.getValue("ParentId"); 202 | if (parentId == nullptr) { 203 | return; 204 | } 205 | const string id = ch2str(attrs.getValue("Id")); 206 | const string transcodedParentId = ch2str(parentId); 207 | auto match = answerCounts.find(transcodedParentId); 208 | if (match != answerCounts.end()) { 209 | db->Put( 210 | leveldb::WriteOptions(), 211 | "a_"+transcodedParentId+"_"+std::to_string(match->second), 212 | jsonize(attrs) 213 | ); 214 | answerCounts[transcodedParentId] += 1; 215 | commentCounts[id] = 0; 216 | } 217 | } else { 218 | bool matches = false; 219 | 220 | const string tagsStr = ch2str(tags); 221 | 222 | for (int i = 0; i < tagNames.size(); ++i) { 223 | matches = tagsStr.find("<"+tagNames[i]+">") != string::npos; 224 | if (matches) break; 225 | } 226 | 227 | if (matches) { 228 | const string id = ch2str(attrs.getValue("Id")); 229 | const string postType = ch2str(attrs.getValue("PostTypeId")); 230 | 231 | if (postType == "1") { 232 | db->Put( 233 | leveldb::WriteOptions(), 234 | "p_"+id, 235 | jsonize(attrs) 236 | ); 237 | answerCounts[id] = 0; 238 | commentCounts[id] = 0; 239 | } else { 240 | const XMLCh* parentId = attrs.getValue("ParentId"); 241 | if (parentId == nullptr) { 242 | return; 243 | } 244 | const string transcodedParentId = ch2str(parentId); 245 | auto match = answerCounts.find(transcodedParentId); 246 | if (match != answerCounts.end()) { 247 | db->Put( 248 | leveldb::WriteOptions(), 249 | "a_"+transcodedParentId+"_"+std::to_string(match->second), 250 | jsonize(attrs) 251 | ); 252 | answerCounts[transcodedParentId] += 1; 253 | commentCounts[id] = 0; 254 | } 255 | } 256 | 257 | } 258 | } 259 | } 260 | } 261 | } 262 | }; 263 | 264 | 265 | int main(int argc, const char ** argv) { 266 | for (int i = 1; i < argc; ++i) { 267 | tagNames.push_back(argv[i]); 268 | } 269 | try { 270 | XMLPlatformUtils::Initialize(); 271 | } catch (const XMLException& e) { 272 | return 1; 273 | } 274 | 275 | leveldb::Options options; 276 | options.create_if_missing = true; 277 | leveldb::DB::Open(options, "leveldb", &db); 278 | 279 | SAXParser *parser = new SAXParser(); 280 | MySAXHandler *handler = new MySAXHandler(); 281 | parser->setDocumentHandler(handler); 282 | ZeroPaddedStdInInputSource src; 283 | parser->parse(src); 284 | 285 | ZeroSeparatedBinFileInputStream::next(); 286 | handler->setComments(); 287 | parser->parse(src); 288 | 289 | ZeroSeparatedBinFileInputStream::next(); 290 | handler->setUsers(); 291 | parser->parse(src); 292 | 293 | delete db; 294 | 295 | return 0; 296 | } 297 | -------------------------------------------------------------------------------- /sqlite_score/score.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | SQLITE_EXTENSION_INIT1 4 | 5 | 6 | // ported from DevDocs' searcher.coffee 7 | 8 | void match_fuzzy( 9 | const char* needle, const char* haystack, 10 | int* start, int* len, int* needle_len 11 | ) { 12 | int i = 0, j = 0; 13 | for (; needle[i] != 0; ++i) { 14 | while(haystack[j] != 0) { 15 | if (needle[i] == haystack[j++]) { 16 | if (*start == -1) *start = j - 1; // first matched char 17 | *len = j - *start; 18 | goto outer; 19 | } 20 | } 21 | *start = -1; // end of haystack, char not found 22 | return; 23 | outer: continue; 24 | } 25 | if (needle_len) 26 | *needle_len = i; 27 | } 28 | 29 | int max(int a, int b) { 30 | if (a > b) return a; 31 | else return b; 32 | } 33 | 34 | int score_exact(int match_index, int match_len, const char* value) { 35 | int score = 100, value_len = strlen(value); 36 | // Remove one point for each unmatched character. 37 | score -= (value_len - match_len); 38 | if (match_index > 0) { 39 | if (value[match_index - 1] == '.') { 40 | // If the character preceding the query is a dot, assign the same 41 | // score as if the query was found at the beginning of the string, 42 | // minus one. 43 | score += (match_index - 1); 44 | } else if (match_len == 1) { 45 | // Don't match a single-character query unless it's found at the 46 | // beginning of the string or is preceded by a dot. 47 | return 0; 48 | } else { 49 | // (1) Remove one point for each unmatched character up to 50 | // the nearest preceding dot or the beginning of the 51 | // string. 52 | // (2) Remove one point for each unmatched character 53 | // following the query. 54 | int i = match_index - 2; 55 | while (i >= 0 && value[i] != '.') --i; 56 | score -= (match_index - i) + // (1) 57 | (value_len - match_len - match_index); // (2) 58 | } 59 | // Remove one point for each dot preceding the query, except for the 60 | // one immediately before the query. 61 | int separators = 0, 62 | i = match_index - 2; 63 | while (i >= 0) { 64 | if (value[i] == '.') { 65 | separators += 1; 66 | } 67 | i--; 68 | } 69 | score -= separators; 70 | } 71 | 72 | // Remove five points for each dot following the query. 73 | int separators = 0; 74 | int i = value_len - match_len - match_index - 1; 75 | while (i >= 0){ 76 | if (value[match_index + match_len + i] == '.') { 77 | separators += 1; 78 | } 79 | i--; 80 | } 81 | score -= separators * 5; 82 | 83 | return max(1, score); 84 | } 85 | 86 | int score_fuzzy(int match_index, int match_len, const char* value) { 87 | if (match_index == 0 || value[match_index-1] == '.') { 88 | return max(66, 100 - match_len); 89 | } else { 90 | if (value[match_index + match_len - 1] == 0) { 91 | return max(33, 67 - match_len); 92 | } else { 93 | return max(1, 34 - match_len); 94 | } 95 | } 96 | } 97 | 98 | static void scoreFunc( 99 | sqlite3_context *context, 100 | int argc, 101 | sqlite3_value **argv 102 | ) { 103 | const char* needle = sqlite3_value_text(argv[0]); 104 | const char* haystack = sqlite3_value_text(argv[1]); 105 | int match1 = -1, match1_len, needle_len; 106 | match_fuzzy(needle, haystack, &match1, &match1_len, &needle_len); 107 | if (match1 == -1) { 108 | sqlite3_result_int(context, 0); 109 | return; 110 | } 111 | 112 | if (needle_len == match1_len) { // exact match 113 | sqlite3_result_int(context, score_exact( 114 | match1, match1_len, haystack 115 | )); 116 | return; 117 | } 118 | 119 | int best = score_fuzzy(match1, match1_len, haystack); 120 | int last_index_of_dot = -1, i; 121 | for (i = 0; haystack[i] != 0; ++i) { 122 | if (haystack[i] == '.') last_index_of_dot = i; 123 | } 124 | if (last_index_of_dot != -1) { 125 | int match2 = -1, match2_len; 126 | match_fuzzy( 127 | needle, haystack + last_index_of_dot + 1, &match2, &match2_len, 128 | 0 129 | ); 130 | if (match2 != -1) { 131 | best = max(best, 132 | score_fuzzy(match2, match2_len, haystack + last_index_of_dot + 1) 133 | ); 134 | } 135 | } 136 | sqlite3_result_int(context, best); 137 | } 138 | 139 | 140 | #ifdef _WIN32 141 | __declspec(dllexport) 142 | #endif 143 | int sqlite3_extension_init( 144 | sqlite3 *db, 145 | char **pzErrMsg, 146 | const sqlite3_api_routines *pApi 147 | ) { 148 | SQLITE_EXTENSION_INIT2(pApi) 149 | sqlite3_create_function(db, "zestScore", 2, SQLITE_ANY, 0, scoreFunc, 0, 0); 150 | return 0; 151 | } -------------------------------------------------------------------------------- /src/cljs/zest/core.cljs: -------------------------------------------------------------------------------- 1 | (ns zest.core 2 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]) 3 | (:require [reagent.core :as reagent] 4 | [cljs.core.async :as async] 5 | [clojure.set :refer [union]] 6 | [cljsjs.react] 7 | [goog.net.XhrIo] 8 | [zest.settings] 9 | [zest.docs.registry] 10 | [zest.docs.stackoverflow] 11 | [zest.searcher] 12 | [zest.docs.devdocs])) 13 | 14 | (defn get-binary-path [filename] 15 | (let [dir (.-__dirname js/window) 16 | path (.require js/window "path")] 17 | (.join path (.dirname path dir) filename))) 18 | 19 | (def so-db (atom nil)) 20 | 21 | (defn set-so-db [] 22 | (reset! so-db 23 | (let [levelup (.require js/window "levelup") 24 | path (.require js/window "path")] 25 | (levelup (.join path (zest.docs.registry/get-so-root) 26 | "leveldb"))))) 27 | 28 | (set-so-db) 29 | 30 | (def so-index 31 | (let 32 | [mkdirp (.require js/window "mkdirp") 33 | path (.require js/window "path")] 34 | (.sync mkdirp (zest.docs.registry/get-so-root)) 35 | (.join path (zest.docs.registry/get-so-root) "lucene"))) 36 | 37 | (defn normalize-str [s] 38 | (-> 39 | s 40 | (.toLowerCase) 41 | (.replace "..." "") 42 | (.replace (js/RegExp. "\\ event$") "") 43 | (.replace (js/RegExp. "\\.+" "g") ".") 44 | (.replace (js/RegExp. "\\(\\w+?\\)$") "") 45 | (.replace (js/RegExp. "\\s" "g") "") 46 | (.replace "()" "") 47 | ; separators: 48 | (.replace (js/RegExp. "\\:?\\ |#|::|->|\\$(?=\\w)" "g") "."))) 49 | 50 | (defn insert-doc [prep doc] 51 | (let [res (async/chan)] 52 | (.run 53 | prep 54 | (normalize-str (.-name (.-contents doc))) 55 | (.-name (.-contents doc)) 56 | (.-docset doc) 57 | (.-path (.-contents doc)) 58 | (fn [] (go (async/>! res true)))) 59 | res)) 60 | 61 | (def symbol-db (atom nil)) 62 | 63 | (def extension-path 64 | (let [path (.require js/window "path")] 65 | (.join path 66 | (.dirname path (.-__dirname js/window)) 67 | "sqlite_score" 68 | "zest_score.sqlext"))) 69 | 70 | (defn open-symbol-db [cb] (let [path (.require js/window "path") 71 | sqlite3 (.require js/window "sqlite3") 72 | Database (.-Database sqlite3) 73 | db-path (.join path (zest.docs.registry/get-devdocs-root) "symbols") 74 | d (Database. db-path cb)] 75 | (.loadExtension d extension-path 76 | (fn [e] (.log js/console e))) 77 | (reset! symbol-db d))) 78 | 79 | (defn rebuild-symbol-db [] 80 | (let [sqlite3 (.require js/window "sqlite3") 81 | Database (.-Database sqlite3) 82 | path (.require js/window "path") 83 | db-chan (let [db-path (.join path (zest.docs.registry/get-devdocs-root) "new_symbols")] 84 | (go (async/! ret true)))))) 104 | (do 105 | (if (= (mod @i 1000) 999) 106 | (.log js/console (inc @i))) 107 | (reset! i (inc @i)) 108 | 109 | (async/ 0 " docsets-where 144 | " ORDER BY score DESC LIMIT 100")) 145 | args (array query)] 146 | (if docsets (.apply (.-push args) args 147 | (.map docsets #(str % "%")))) 148 | (.apply 149 | (.-all prep) 150 | prep 151 | (.concat 152 | args 153 | (array 154 | (fn [e data] 155 | (go (async/>! res (map 156 | #(js-obj "docset" (.-docset %) 157 | "contents" (js-obj "path" (.-path %) 158 | "name" (.-s %))) 159 | data))))))) 160 | res)) 161 | 162 | (defn do-match-chunks [query docsets cb] 163 | (.interrupt @symbol-db) 164 | (go (reset! 165 | results 166 | (concat 167 | (async/" 269 | (nth files @i) 270 | "" 271 | (.highlight 272 | search-index 273 | (escape-html 274 | (zest.docs.stackoverflow/unfluff 275 | (aget db-cache path))) 276 | @query))) 277 | (if (< @i (- (count files) 1)) 278 | (do (reset! i (+ @i 1)) (next)) 279 | (do (cb @res))))))] 280 | (next))) 281 | 282 | set-600ms-focus 283 | (fn [] 284 | (reset! input-focus true) 285 | (if focus-id (.clearTimeout js/window @focus-id)) 286 | (reset! focus-id (.setTimeout js/window #(reset! input-focus false) 600))) 287 | hash (reagent/atom "#") 288 | set-hash 289 | (fn [new-hash] 290 | (if (nil? new-hash) 291 | (set! (.-scrollTop (.getElementById js/document "right-contents")) 0) 292 | (.setImmediate 293 | js/window 294 | (fn [] 295 | ; in case new-hash = current hash: 296 | (.send (.getElementById js/document "right-contents") "hash" "") 297 | (.setImmediate 298 | js/window 299 | #(.send (.getElementById js/document "right-contents") "hash" new-hash)))))) 300 | 301 | async-num (atom 0) 302 | async-set-html 303 | (fn [new-class new-html done-cb] 304 | (let 305 | [target (.getElementById js/document "right-contents") 306 | temp (atom (.createElement js/document "div")) 307 | cur-num (+ @async-num 1) 308 | 309 | attrs-to-array 310 | (fn [attrs] 311 | (if attrs 312 | (.map 313 | (apply array (range (.-length attrs))) 314 | #(js-obj 315 | "name" (.-name (aget attrs %)) 316 | "value" (.-value (aget attrs %)))) 317 | attrs)) 318 | 319 | proceed 320 | (fn proceed [] 321 | (if (= cur-num @async-num) 322 | (if (.-firstChild @temp) 323 | (let [first (.-firstChild @temp)] 324 | (if (or (= (.-nodeType first) 1) 325 | (= (.-nodeType first) 3)) 326 | (.send target "add" 327 | (if (= (.-nodeType first) 1) 328 | (.-tagName first) 329 | (.-nodeType first)) 330 | (if (= (.-nodeType first) 1) 331 | (.-innerHTML first) 332 | (.-data first)) 333 | (attrs-to-array (.-attributes first)))) 334 | (.removeChild @temp first) 335 | (.setImmediate js/window proceed)) 336 | (done-cb))))] 337 | 338 | (reset! async-num (+ @async-num 1)) 339 | (reset! html new-html) 340 | (set! (.-innerHTML @temp) new-html) 341 | (.send target "reset" new-class) 342 | (proceed))) 343 | 344 | activate-item 345 | (fn [docset entry] 346 | (.log js/console docset entry) 347 | (if (= 0 (.indexOf docset "stackoverflow")) 348 | (let [] 349 | (set! (.-scrollTop (.getElementById js/document "right-contents")) 0) 350 | (.get 351 | @so-db 352 | (str "p_" entry) 353 | (fn [e json] 354 | (let [data (.parse js/JSON json)] 355 | (aset (.getElementById js/document "right-contents") "className" 356 | "") 357 | (go (async-set-html 358 | "" 359 | (async/ e .-target .-value)] 431 | (.findInPage (get-contents) q)))}] 432 | [:a {:class "btn-flat"} 433 | [:i {:class "material-icons" 434 | :on-click #(.findInPage (get-contents) 435 | (.-value (get-search-input)) 436 | (js-obj "forward" false))} 437 | "skip_previous"]] 438 | [:a {:class "btn-flat"} 439 | [:i {:class "material-icons" 440 | :on-click #(.findInPage (get-contents) 441 | (.-value (get-search-input)))} 442 | "skip_next"]]])) 443 | [:webview 444 | {:id "right-contents" 445 | :src (.join path 446 | (.-__dirname js/window) 447 | "viewer.html") 448 | :preload (.join path 449 | (.-__dirname js/window) 450 | "viewer.js")}]])})) 451 | 452 | refresh 453 | (fn [] 454 | (let [entry (nth @results @index) 455 | entry-path (.-path (.-contents entry))] 456 | (if (= "__FTS__" entry-path) 457 | (fts-results (.search (get-search-index) @query) 458 | #(async-set-html 459 | "" 460 | % 461 | (fn [] (set! (.-scrollTop 462 | (.getElementById js/document "right-contents")) 0)))) 463 | (activate-item (.-docset entry) (.-contents entry))))) 464 | 465 | render-item 466 | (fn [i item] 467 | ^{:key (str @query (str i))} 468 | [:a 469 | {:class (str (if (= @index i) "collection-item active" 470 | "collection-item") 471 | (if (not (= (.-path (.-contents item)) "__FTS__")) 472 | (str " _list-item " "_icon-" 473 | (nth (.split (.-docset item) "~") 0)) 474 | "")) 475 | :href "#" 476 | :on-click (fn [] 477 | (reset! index i) 478 | (refresh) 479 | (.focus (.getElementById js/document "searchInput")))} 480 | (.-name (.-contents item))]) 481 | 482 | section 483 | (fn [docset type] 484 | [:div {:class "collection"} 485 | (for 486 | [entry (get-in @docset-type-items [docset type])] 487 | ^{:key (str docset "_" (.-name type) "_" (.-path entry) "_" (.-name entry))} 488 | 489 | [:a 490 | {:class "collection-item" 491 | :href "#" 492 | :on-click #(activate-item docset entry)} 493 | (.-name entry)])]) 494 | 495 | fts-suggestions 496 | (fn [] 497 | (if (> (count @search-results) 0) 498 | (do [:div {:class "collection with-header"} 499 | [:div {:class "collection-header z-depth-1"} 500 | [:strong "Stack Overflow"]] 501 | (map 502 | (fn [res] 503 | ^{:key (js/btoa (js/unescape (js/encodeURIComponent res)))} 504 | [:a 505 | {:href "#" 506 | :class "collection-item" 507 | :on-click #(activate-item "stackoverflow" 508 | (nth (.split res ";") 0))} 509 | (nth (.split res ";") 1)]) 510 | @search-results)]) 511 | [:div]))] 512 | 513 | (reagent/create-class 514 | {:reagent-render 515 | (fn [] 516 | [:div {:style {:height "100%"}} 517 | [:div {:id "left"} 518 | (if (not (nil? @cur-docsets)) 519 | [:div {:class "searchDocset"} 520 | [:span "Showing results from '"] 521 | [:strong @cur-docsets] 522 | [:span "' only"]]) 523 | [:input 524 | {:id "searchInput" 525 | :type "text" 526 | :on-blur 527 | (fn [e] (if @input-focus 528 | (.focus (.getElementById js/document "searchInput")))) 529 | :on-key-down 530 | (fn [e] 531 | (case (.-key e) 532 | "ArrowDown" (reset! index (mod (+ @index 1) (count @results))) 533 | "ArrowUp" (reset! index (mod (- @index 1) (count @results))) 534 | "Escape" (do (set! (.-value (.-target e)) "") (set-query "")) 535 | "Enter" ()) 536 | (refresh) 537 | (set-600ms-focus) 538 | false) 539 | :on-change 540 | (fn [e] 541 | (let [q (-> e .-target .-value)] 542 | (set-query q)))}] 543 | [:div {:class "collapsible tree"} 544 | (if (= 0 (count @results)) 545 | (doall (for [docset 546 | (map (fn [x] {:name x :label x}) @docsets-list)] 547 | ^{:key (:name docset)} 548 | [:div 549 | [:div {:class 550 | (str "collapsible-header _list-item _icon-" 551 | (nth (.split (:name docset) "~") 0)) 552 | :on-click 553 | (fn [] 554 | (if (nil? (get @docset-types (:name docset))) 555 | (reset! 556 | docset-types 557 | (assoc @docset-types 558 | (:name docset) 559 | (.-types (zest.docs.devdocs/get-from-cache (:name docset))))) 560 | (reset! docset-types (dissoc @docset-types (:name docset)))))} 561 | (:label docset)] 562 | (doall (for [type (get @docset-types (:name docset))] 563 | (let [] 564 | ^{:key (str (:name docset) "/" (.-name type))} 565 | [:div {:class "collapsible level2"} 566 | [:div {:class "collapsible-header" 567 | :on-click 568 | (fn [] 569 | (if (nil? (get-in @docset-type-items [(:name docset) type])) 570 | (reset! docset-type-items 571 | (assoc-in @docset-type-items [(:name docset) type] 572 | (filter 573 | #(= (.-type %) (.-name type)) 574 | (.-entries (zest.docs.devdocs/get-from-cache (:name docset)))))) 575 | (reset! docset-type-items 576 | (dissoc (get @docset-type-items (:name docset)) type))))} 577 | 578 | (.-name type)] 579 | [section (:name docset) type]])))])) 580 | [:div {:class "collection"} (doall (for [[i item] (map-indexed vector @results)] 581 | (render-item i item) 582 | ))]) 583 | (if (> (count @query) 0) (fts-suggestions))]] 584 | (set! (.-setQuery js/window) 585 | (fn [q docsets] 586 | (set! 587 | (.-value 588 | (.getElementById js/document "searchInput")) 589 | q) 590 | (set-query-with-cb 591 | q docsets 592 | #(let [entry (nth @results 0)] 593 | (activate-item (.-docset entry) 594 | (.-contents entry)))))) 595 | [right-class] 596 | [zest.settings/register-settings]])}))) 597 | 598 | (defn mount-root 599 | [] 600 | (set! (.-onkeydown js/document) 601 | (fn [e] 602 | (if (= (.-keyCode e) 27) 603 | (do 604 | (.closeModal (.$ js/window ".modal")))))) 605 | (reagent/render 606 | [main-page] 607 | (.getElementById js/document "app"))) 608 | 609 | (defn make-devdocs-loop [] 610 | (.log js/console "make-devdocs-loop") 611 | (go-loop [] 612 | (let [data (async/ (count @query) 0) 616 | (set-query @query)) 617 | (recur)))) 618 | 619 | (def devdocs-loop (make-devdocs-loop)) 620 | 621 | (defn before-figwheel-reload [] 622 | (.log js/console "before") 623 | (.close @so-db) 624 | (.close @symbol-db) 625 | (zest.searcher/stop-all-searchers) 626 | (.removeEventListener 627 | (.-body js/document) 628 | "figwheel.before-js-reload" 629 | before-figwheel-reload) 630 | (async/close! devdocs-loop)) 631 | 632 | (defn add-figwheel-handler [] 633 | (.addEventListener 634 | (.-body js/document) 635 | "figwheel.before-js-reload" 636 | before-figwheel-reload)) 637 | 638 | (defn init! 639 | [] 640 | (add-figwheel-handler) 641 | (zest.searcher/new-searcher so-index) 642 | (open-symbol-db nil) 643 | (mount-root) 644 | (.processCmdLine (.-app (.-remote (js/require "electron"))) 645 | (.-argv (.-process (.-remote (js/require "electron")))))) 646 | 647 | (defn on-figwheel-reload [] 648 | (init!)) 649 | -------------------------------------------------------------------------------- /src/cljs/zest/docs/devdocs.cljs: -------------------------------------------------------------------------------- 1 | (ns zest.docs.devdocs 2 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]) 3 | (:require [reagent.core :as reagent] 4 | [cljs.core.async :as async] 5 | [zest.docs.registry] 6 | [medley.core :refer [interleave-all]])) 7 | 8 | (def docset-cache (js-obj)) 9 | (def docset-db-cache (js-obj)) 10 | 11 | (defn get-from-cache [dir] 12 | (if (nil? (aget docset-cache dir)) 13 | (let [path (.require js/window "path") 14 | fs (.require js/window "fs") 15 | devdocs-root (zest.docs.registry/get-devdocs-docs-root) 16 | json (.parse js/JSON 17 | (.readFileSync 18 | (.require js/window "fs") 19 | (.join path devdocs-root dir "index.json") "utf8"))] 20 | 21 | 22 | (aset docset-cache dir json) 23 | (aset docset-db-cache dir 24 | (.parse js/JSON (.readFileSync 25 | fs 26 | (.join path devdocs-root dir "db.json") 27 | "utf8"))) 28 | json) 29 | (aget docset-cache dir))) 30 | 31 | 32 | (defn get-entries [dir] 33 | (map #(js-obj "docset" dir "contents" %) 34 | (.-entries (zest.docs.devdocs/get-from-cache dir)))) 35 | 36 | (defn get-all-entries [data] 37 | ; interleave to give each docset equal chance of being found 38 | (apply interleave-all (map (fn [x] (get-entries x)) data))) 39 | 40 | (def entries 41 | (reagent/atom (get-all-entries @zest.docs.registry/installed-devdocs-atom))) 42 | -------------------------------------------------------------------------------- /src/cljs/zest/docs/registry.cljs: -------------------------------------------------------------------------------- 1 | (ns zest.docs.registry 2 | (:require-macros [cljs.core.async.macros :refer [go]]) 3 | (:require [reagent.core :as reagent] 4 | [cljs.core.async :as async])) 5 | 6 | 7 | (defn get-so-root [] 8 | (let [electron (.require js/window "electron") 9 | path (.require js/window "path")] 10 | (.join path 11 | (.getPath (.-app (.-remote electron)) "userData") 12 | "so"))) 13 | 14 | (defn get-devdocs-root [] 15 | (let [electron (.require js/window "electron") 16 | path (.require js/window "path")] 17 | (.join path 18 | (.getPath (.-app (.-remote electron)) "userData") 19 | "devdocs"))) 20 | 21 | (defn get-devdocs-docs-root [] 22 | (let [path (.require js/window "path")] 23 | (.join path (get-devdocs-root) "docs"))) 24 | 25 | (defn get-available-devdocs [cb] 26 | (let [electron (.require js.window "electron") 27 | fs (.require js/window "fs") 28 | mkdirp (.require js/window "mkdirp") 29 | path (.require js/window "path") 30 | request (.require js/window "request") 31 | devdocs-json (.join path 32 | (.getPath (.-app (.-remote electron)) "userData") 33 | "devdocs.json") 34 | 35 | fetch 36 | (fn [] 37 | (request "https://devdocs.io/docs.json" 38 | (fn [error response body] 39 | (.writeFileSync fs devdocs-json body) 40 | (cb (.parse js/JSON body)))))] 41 | 42 | (.sync mkdirp (get-devdocs-docs-root)) 43 | (if (and (.existsSync fs devdocs-json) 44 | (.isFile (.statSync fs devdocs-json))) 45 | (try 46 | (cb (.parse js/JSON (.readFileSync fs devdocs-json))) 47 | (catch js/Error e 48 | (.log js/console (str "Error reading devdocs.json: " e "; fetching")) 49 | (fetch))) 50 | (do 51 | (.log js/console "devdocs.json missing - fetching") 52 | (fetch))))) 53 | 54 | 55 | (defn get-installed-devdocs [] 56 | (let 57 | [fs (.require js/window "fs") 58 | mkdirp (.require js/window "mkdirp")] 59 | (.sync mkdirp (get-devdocs-docs-root)) 60 | (.readdirSync fs (get-devdocs-docs-root)))) 61 | 62 | (def installed-devdocs-atom (reagent/atom 63 | (zest.docs.registry/get-installed-devdocs))) 64 | 65 | (def installed-devdocs-chan (async/chan)) 66 | 67 | (defn update-installed-devdocs [] 68 | (let [installed (get-installed-devdocs)] 69 | (go (async/>! installed-devdocs-chan installed)) 70 | (reset! installed-devdocs-atom installed))) 71 | -------------------------------------------------------------------------------- /src/cljs/zest/docs/stackoverflow.cljs: -------------------------------------------------------------------------------- 1 | (ns zest.docs.stackoverflow 2 | (:require-macros [cljs.core.async.macros :refer [go]]) 3 | (:require [reagent.core :as reagent] 4 | [cljs.core.async :as async])) 5 | 6 | 7 | (defn unfluff 8 | [html] 9 | (let 10 | [parse5 (.require js/window "parse5") 11 | res (reagent/atom "") 12 | SAXParser (.-SAXParser parse5) 13 | parser (SAXParser. ())] 14 | 15 | (.on parser "text" (fn [text] (reset! res (str @res text)))) 16 | (.write parser html) 17 | @res)) 18 | 19 | (defn process-so-post [data with-users] 20 | (let 21 | [process-tags 22 | (fn [tags] 23 | (if tags (.map 24 | (.match tags (js/RegExp. "<[^>]+>" "g")) 25 | #(.substring % 1 (- (.-length %) 1))))) 26 | 27 | process-answer 28 | (fn [answer] 29 | (let [ret-data answer 30 | ret (async/chan) 31 | cStream (.createReadStream 32 | @zest.core/so-db 33 | (js-obj "gt" (str "c_" (.-Id answer) "_") 34 | "lt" (str "c_" (.-Id answer) "_a"))) 35 | 36 | all (atom 0) 37 | done (atom 0) 38 | ended (atom false) 39 | 40 | check-finished 41 | (fn [] 42 | (if (and @ended (= @all @done)) (go (async/>! ret ret-data))))] 43 | 44 | (aset ret-data "comments" (array)) 45 | (aset ret-data "Tags" (process-tags (aget ret-data "Tags"))) 46 | (if (and (aget data "AcceptedAnswerId") 47 | (= (aget ret-data "Id") (aget data "AcceptedAnswerId"))) 48 | (aset ret-data "Accepted" true)) 49 | 50 | (.on cStream "data" 51 | (fn [v] 52 | (reset! all (inc @all)) 53 | (let [comment (.parse js/JSON (.-value v))] 54 | (.push (aget ret-data "comments") comment) 55 | (if (and with-users (nil? (.-UserDisplayName comment))) 56 | (.get @zest.core/so-db (str "u_" (.-UserId comment)) 57 | (fn [e ret] 58 | (.log js/console ret) 59 | (aset comment "UserDisplayName" 60 | (.-DisplayName (.parse js/JSON ret))) 61 | (reset! done (inc @done)) 62 | (check-finished))) 63 | (reset! done (inc @done)))))) 64 | (.on cStream "end" (fn [] 65 | (reset! ended true) 66 | (check-finished))) 67 | ret)) 68 | 69 | ret-data data 70 | ret (async/chan) 71 | started (atom 0) 72 | finished (atom 0) 73 | ended (atom false) 74 | cStream (.createReadStream 75 | @zest.core/so-db 76 | (js-obj "gt" (str "c_" (.-Id data) "_") 77 | "lt" (str "c_" (.-Id data) "_a"))) 78 | check-finished 79 | (fn [] 80 | (if (and (= @started @finished) @ended) 81 | (go (async/>! ret ret-data))))] 82 | 83 | (aset ret-data "answers" (array)) 84 | (aset ret-data "comments" (array)) 85 | (aset ret-data "Tags" (process-tags (aget ret-data "Tags"))) 86 | 87 | (.on cStream "data" 88 | (fn [v] 89 | (let [comment (.parse js/JSON (.-value v))] 90 | (.push (aget ret-data "comments") comment)))) 91 | 92 | (.on cStream "end" 93 | (fn [] 94 | (let [aStream (.createReadStream 95 | @zest.core/so-db 96 | (js-obj "gt" (str "a_" (.-Id data) "_") 97 | "lt" (str "a_" (.-Id data) "_a")))] 98 | (.on aStream "data" 99 | (fn [v] 100 | (reset! started (inc @started)) 101 | (let [answer (.parse js/JSON (.-value v))] 102 | (go 103 | (let [ans-data (async/ (.-length lines) 1) 34 | (do 35 | (async/>! ch (.shift lines)) 36 | (recur)) 37 | (reset! last (.shift lines))))))))) 38 | 39 | (def search-num (atom 0)) 40 | 41 | (defn search [index query] 42 | (let [res (async/chan) 43 | res-data (array) 44 | cur-search-num (+ 1 @search-num)] 45 | (reset! search-num cur-search-num) 46 | (if (contains? @searching index) 47 | (do (.kill (get @cur-searchers index) "SIGKILL") 48 | (new-searcher index))) 49 | (reset! searching (conj @searching index)) 50 | (.write (.-stdin (get @cur-searchers index)) (str query "\n")) 51 | (go-loop 52 | [] 53 | ; avoid old queries hijacking new queries' lines 54 | ; or overwriting new queries' results 55 | (if (= cur-search-num @search-num) 56 | (let [line (async/! res res-data) 63 | (reset! searching (disj @searching index))))))) 64 | res)) 65 | 66 | (defn stop-all-searchers [] 67 | (doall (for [s (vals @cur-searchers)] 68 | (.kill s "SIGKILL")))) 69 | -------------------------------------------------------------------------------- /src/cljs/zest/settings.cljs: -------------------------------------------------------------------------------- 1 | (ns zest.settings 2 | (:require-macros [cljs.core.async.macros :refer [go go-loop]]) 3 | (:require [cljs.core.async :as async] 4 | [reagent.core :as reagent] 5 | [zest.docs.registry] 6 | [zest.docs.devdocs])) 7 | 8 | (def visible (reagent/atom false)) 9 | (def devdocs-visible (reagent/atom false)) 10 | (def devdocs-reindexing (reagent/atom false)) 11 | (def devdocs-reindexing-progress (reagent/atom "")) 12 | (def so-visible (reagent/atom false)) 13 | (def downloading (reagent/atom {})) 14 | (def downloading-error (reagent/atom {})) 15 | (def so-indexing (reagent/atom false)) 16 | (def so-downloading (reagent/atom false)) 17 | (def so-download-progress (reagent/atom 0)) 18 | (def so-download-total (reagent/atom 0)) 19 | (def so-download-peers (reagent/atom 0)) 20 | (def so-dl-speed (reagent/atom 0)) 21 | (def so-ul-speed (reagent/atom 0)) 22 | (def so-grep-progress (reagent/atom nil)) 23 | (def so-index-progress (reagent/atom nil)) 24 | (def so-index-tags (reagent/atom #{})) 25 | (def so-archives-total (reagent/atom nil)) 26 | (def so-archives-available 27 | (let [fs (.require js/window "fs") 28 | path (.require js/window "path") 29 | done-filename (.join path (zest.docs.registry/get-so-root) 30 | "archive" "zest_done")] 31 | (reagent/atom 32 | (and 33 | (.existsSync fs done-filename) 34 | (.isFile (.statSync fs done-filename)))))) 35 | 36 | (defn async-rimraf [path] 37 | (let [res (async/chan) 38 | rimraf (js/require "rimraf")] 39 | (go (rimraf path #(go (async/>! res (or % true))))) 40 | res)) 41 | 42 | (defn async-add-file [idx name contents] 43 | (let [ret (async/chan)] 44 | (.setImmediate 45 | js/window #(go (.addFile idx name contents) 46 | (async/>! ret true))) 47 | ret)) 48 | 49 | (defn devdocs-rebuild-index [] 50 | (reset! devdocs-reindexing true) 51 | (reset! devdocs-reindexing-progress "") 52 | (let [path (.require js/window "path") 53 | fs (.require js/window "fs-extra") 54 | LuceneIndex 55 | (.-LuceneIndex (.require js/window "nodelucene")) 56 | idx-chan (let [new-lucene-path (.join path 57 | (zest.docs.registry/get-devdocs-root) 58 | "new_lucene")] 59 | (go (async/ docs-count 0) 64 | (inc docs-count) 0) 65 | indexed-count (atom 0) 66 | 67 | check-done 68 | (fn [] 69 | (reset! indexed-count (inc @indexed-count)) 70 | (if (= @indexed-count all-count) 71 | (go (.endWriting @idx) 72 | (async/ all-count 0) 101 | (do ; rebuild sqlite and lucene indices in parallel 102 | (go 103 | (async/! ret (+ (.parseFloat js/window (nth vals 0)) 232 | (.parseFloat js/window (nth vals 1)) 233 | (.parseFloat js/window (nth vals 2))))))) 234 | ret)) 235 | 236 | (defn start-so-indexing [] 237 | (reset! so-index-progress 0) 238 | (let [levelup (.require js/window "levelup") 239 | path (.require js/window "path") 240 | fs (.require js/window "fs-extra") 241 | db (levelup. 242 | (.join path (zest.docs.registry/get-so-root) "new_index" "leveldb")) 243 | rStream (.createReadStream 244 | db 245 | (js-obj "gt" "p_" 246 | "lt" "p_a")) 247 | 248 | LuceneIndex 249 | (.-LuceneIndex (.require js/window "nodelucene")) 250 | idx (LuceneIndex. (.join path (zest.docs.registry/get-so-root) 251 | "new_index" "lucene")) 252 | 253 | render-answer-blob 254 | (fn [data] 255 | (str (.-Title data) " " 256 | (zest.docs.stackoverflow/unfluff (.-Body data)) 257 | (apply str (.map (.-comments data) #(str " " (.-Text %)))))) 258 | 259 | render-blob 260 | (fn [data] 261 | (str (.-Title data) " " 262 | (zest.docs.stackoverflow/unfluff (.-Body data)) 263 | (apply str (.map (.-comments data) 264 | #(str " " (.-Text %)))) 265 | (apply str (.map (.-answers data) 266 | #(str " " (render-answer-blob %)))))) 267 | 268 | done (atom 0) 269 | started (atom 0) 270 | ended (atom false) 271 | check-all-done 272 | (fn [] 273 | (if (and @ended (= @started @done)) 274 | (do 275 | (.endWriting idx) 276 | (zest.searcher/stop-all-searchers) 277 | (.close 278 | @zest.core/so-db 279 | (.close 280 | db 281 | #(go 282 | (async/