- makes the html/template for /register follow the same formatting
as /apple and /windows
- adds a <title> element
- minor change for consistency's sake
Websockets, in which DERP is based, requires a TLS certificate. At the same time,
if we use a certificate it must be valid... otherwise Tailscale wont connect (does not
have an Insecure option). So there is no option to expose insecure here
- registry file /windows/tailscale.reg is generated, filling in the
associated control server URL
- also includes CLI instructions
- fix /apple incorrect template: 'Url' is supposed to be '.URL'
This series of commit will be adding an embedded DERP server (and STUN) to Headscale,
thus making it completely self-contained and not dependant in other infrastructure.
logs looks like the following
```
2022-03-02T20:43:08Z DBG Expanding alias=app-test
2022-03-02T20:43:08Z DBG Expanding alias=kube-test
2022-03-02T20:43:08Z DBG Expanding alias=test
2022-03-02T20:43:08Z WRN No IPs found with the alias test
2022-03-02T20:43:08Z DBG Expanding alias=prod
2022-03-02T20:43:08Z WRN No IPs found with the alias prod
2022-03-02T20:43:08Z DBG Expanding alias=prod
2022-03-02T20:43:08Z WRN No IPs found with the alias prod
```
- `preauthkey`, `authkey`, `pre` are aliases for `preauthkey` command
- `ls`, `show` are aliases for `list` subcommand
- `c`, `new` are aliases for `create` subcommand
- `revoke`, `exp`, `e` are aliases for `expire` subcommand
- `apikey`, `api` are aliases for `apikeys` command
- `ls`, `show` are aliases for `list` subcommand
- `c`, `new` are aliases for `create` subcommand
- `revoke`, `exp`, `e` are aliases for the `expire` subcommand
- `namespace`, `ns`, `user`, `users` are aliases for `namespaces`
command
- `c`, `new` are aliases for the `create` subcommand
- `delete` is an alias for the `destroy` subcommand
- `mv` is an alias for the `rename` subcommand
- `ls`, `show` are aliases for the `list` subcommand
- `node`, `machine`, `machines` are aliases for `nodes` command
- `ls`, `show` aliases for `list` subcommand
- `logout`, `exp`, `e` are aliases for `expire` subcommand
- `del` is an alias for `delete` subcommand
This commit removes the need for datatypes.JSON and makes the code a bit
cleaner by allowing us to use proper types throughout the code when it
comes to hostinfo and other datatypes on the machine object.
This allows us to remove alot of unmarshal/marshal operations and remove
a lot of obsolete error checks.
This following commits will clean away a lot of untyped data and
uneccessary error checks.
This commit removes the two extra caches (oidc, requested time) and uses
the new central registration cache instead. The requested time is
unified into the main machine object and the oidc key is just added to
the same cache, as a string with the state as a key instead of machine
key.
This commit removes the field from the database and does a DB migration
**removing** all unregistered machines from headscale.
This means that from this version, all machines in the database is
considered registered.
current logic is not safe as it will allow an IP that isnt persisted to
the DB to be given out multiple times if machines joins in quick
succession.
This adds a lock around the "get ip" and machine registration and save
to DB so we ensure thiis isnt happning.
Currently this had to be done three places, which is silly, and outlined
in #294.
After some more tests in tailscale I couldn't replicate the behavior
described in there.
When adding a rule, allowing A to talk to B the reverse connection was
instantly added to B to allow communication to B.
The previous assumption was probably wrong.
Using h.ListAllMachines also listed the current machine in the result. It's unnecessary (I don't know if it's harmful).
Breaking the check with the `matchSourceAndDestinationWithRule` broke the tests. We have a specificity with the '*' destination that isn't symetrical.
I need to think of a better way to do this. It too hard to read.
Rewrite some function to get rid of the dependency on Headscale object. This allows us
to write succinct test that are more easy to review and implement.
The improvements of the tests allowed to write the removal of the tagged hosts
from the namespace as specified here: https://tailscale.com/kb/1068/acl-tags/
This call should be done quite at each modification of a server resources like RequestTags.
When a server changes it's tag we should rebuild the ACL rules.
When a server is added to headscale we also should update the ACLRules.
This commit change the default behaviour and remove the notion of namespaces between the hosts. It allows all namespaces to be only filtered by the ACLs. This behavior is closer to tailsnet.
A hidden thing was implied in this document is that each person should have his own namespace.
Hidden information in spicification isn't good.
Thank's @kradalby for pointing it out.
This commit adds a sponsor/funding section to headscale.
@juanfont and I have discussed this and this arrangement is agreed upon
and hopefully this can bring us to a place in the future were even more
features and prioritization can be put upon the project.
This commit removes the namespace kv worker and related code, now that
we talk over gRPC to the server, and not directly to the DB, we should
not need this anymore.
Headscale commands fail when running them as the current user instead of the user defined in the systemd file. This note provides 2 methods of how to correctly run the headscale commands.
The automatic migration did not pick up this change and it breaks
current setups as it only adds a new field which is empty.
This means that clients who dont request a new IP will not have any IP
at all.
This commit configures the CI to run specific parts of the CI when
relevant changes has been made.
This should help us not have to deal with the integration tests when we
do doc/admin changes.
This commit adds a command to generate a private key for headscale.
Mostly useful for systems were you drive the deployment from another
machine and use a secret management system.
This commit enables the existing gRPC and HTTP API from remote locations
as long as the user can provide a valid API key. This allows users to
control their headscale with the CLI from a workstation. 🎉
This commits introduces a new data model for holding api keys for the
API. The keys are stored in the database with a prefix and a hash and
bcrypt with 10 passes is used to store the hash and it is "one way
safe".
Api keys have an expiry logic similar to pre auth keys.
A key cannot be retrieved after it has created, only verified.
* Resolves an issue where sometimes attempted sends on a closed channel
happened by ensuring the channels remain open for the entire goroutine.
* May be of help with regards to issue #203
- Fix URLs referring to files in this repository
- Better explain that we are creating the headscale directory and running the commands on the host Docker node
- Place instructions to download example config file to use as config file, as recommended steps.
This commit starts restructuring the documentation and updating it to be
compliant with 0.12.x+ releases.
The main change is that the documentation has been rewritten for the
ground up, and hopefully simplified.
The documentation has been split into an official documentation for
running headscale as a binary under Linux with SystemD and a "community"
provided documentation for Docker.
This should make the two documents a lot easier to read and follow than
the mishmash document we had.
This commit converts all the uses of wgkey to the new key interfaces.
It now has specific machine, node and discovery keys and we now should
use them correctly.
Please note the new logic which strips a key prefix (in utils.go) that
is now standard inside tailscale.
In theory we could put it in the database, but to preserve backwards
compatibility and not spend a lot of resources on accounting for both,
we just strip them.
We dont seem to need the wireguard key anymore, we generate a key on
startup based on the new library and the users fetch it from /key.
Clean up app.go and update docs
a nil value, instead of the default value (1h). This resulted in the
preauthkey being created with expiration key '0001-01-01 00:00:00',
which meant the key would not work, because it was already expired.
This commit applies the default expiration time (1h) when a preauthkey
is created without a specific expiration. It also updates an integration
test to make sure this bug does not reoccur.
This commit adds a sentral cache to keep track of clients whom has
requested an expiry time, but were we need to keep hold of it until the
second request comes in.
We should never expose errors via web, it gives attackers a lot of info
(Insert OWASP guide).
Also handle error that didnt separate not found gorm issue and other
errors.
This commits tries to dismantle the complicated "if and or" in the
RegistrationHandler by factoring out the "is Registrated" into a root
if.
This, together with some new comments, should hopefully make it a bit
easier to follow what is happening in all the different cases that needs
to be handled when a Node contacts the registration endpoint.
This commit is trying to DRY up the initiation of the gRPC client in
each command:
It renames the function to CLI instead of GRPC as it actually set up a
CLI client, not a generic grpc client
It also moves the configuration of address, timeout (which is now
consistent) and api to use Viper, allowing users to set it via env vars
and configuration file
This PR adds a new part to the integration test suite which spins up a
new headscale and runs through a scenario of test cases for each
command.
The intent is to check that all commands work as intended and produce
the expected output.
I think they have been pretty well covered, but would appreciate
additional test cases if I have missed some.
Please note: headscale is set up, and teared down for _each_ "test
function" in this file, this means that its more suitable for specific
cases.
This commit is a first in a series of commits migrating the command
interfaces to use the new gRPC client.
As a part of this commit, they have been streamlined and each command
_should_ be a bit more similar and use consistent output.
By using the new output function, we now make sure its always json
(errors and everything) if the user asks for JSON.
This commit moves the routes lookup functions to be subcommands of
Machine, making them a lot simpler and more specific/composable.
It also moves the register command from cli.go into machine, so we can
clear out the extra file.
Finally a toProto function has been added to convert between the machine
database model and the proto/rpc model.
This commit adds a debug command tree, intended to host commands used
for debugging and testing.
It adds a create node/machine command which will be used later to create
machines that can be used to test the registration command.
This commit adds proto rpc definitions for the communication needed for
the CLI interface.
This will allow us to move the rest of the CLI interface over to gRPC
and in the future allow remote access
This commit changes the way CLI and grpc-gateway communicates with the
gRPC backend to socket, instead of localhost. Unauthenticated access now
goes on the socket, while the network interface will require API key (in
the future).
This commit sets up the API and gRPC endpoints and adds authentication
to them. Currently there is no actual authentication implemented but it
has been prepared for API keys.
In addition, there is a allow put in place for gRPC traffic over
localhost. This has two purposes:
1. grpc-gateway, which is the base of the API, connects to the gRPC
service over localhost.
2. We do not want to break current "on server" behaviour which allows
users to use the cli on the server without any fuzz
This does not have to be reviewed, here is some reasoning:
Go (and go mod) is designed for having code available and we need to
check in the generated code to make sure it is "go gettable". If we dont
we give ourselves a headache trying to setup all the ci, tests etc to
install and generate the code before it runs.
Because the code isnt there, the plugins needed to generate the code
fail to install...
I didnt find any good documentation for this, but there is this github
comment:
https://github.com/golang/go/issues/34514#issuecomment-535406759
This commit moves the TLS configuration into a seperate function.
It also wires up the gRPC interface and prepares handing the API
endpoints to the grpc gateway.
* when listing nodes, a namespace is now optional, when it is not
provided, all nodes are shown
* when deleting, and sharing a node, remove the `namespace` flag, it was
superfluous and unused
* when unsharing a node, specify the namespace as an argument not a
flag, making the UX the same as for sharing.
Also refactor the share/unshare code to reuse the shared bits.
This PR will promote fetching the derpmap directly from tailscale, so we
will remove our example, as it might easily get outdated.
Add a derp-example that shows how a user can also add their own derp
server.
There is some weird behaviour that seem to storm the update channel. And
our solution with a central map of update channels isnt particularly
elegant.
For now, replace all the complicated stuff with a simple channel that
checks roughly every 10s if the node is up to date. Only generate and
update if there has been changes.
This tries to make the same functions emit and consume the same type of
data all over the application.
If a function transform data, it should emit new data, not a pointer.
This commit adds some Prometheus metrics to /metrics in headscale.
It will add the standard go metrics, some automatic gin metrics and some
initial headscale specific ones.
Some of them has been added to aid debugging #97 (loop bug)
In the future, we can use the metrics to get rid of the sleep in the
integration tests by checking that our expected number of nodes has been
registered:
```
headscale_machine_registrations_total
```
This commit moves toNode to the bottom of the file, and adds a helper
function for lists of Machines to be converted.
It also adds string helpers for Machines and lists of machines.
Lastly it splits getPeers into getDirectPeers, which exist in the same
namespace, and getShared, which is nodes shared with the namespace.
getPeers is kept as a function putting together the two lists for
convenience.
This commit rewrites a bunch of the code to always use *Machine instead
of a mix of both, and a mix of tailcfg.Node and Machine.
Now we use *Machine, and if tailcfg.Node is needed, it is converted just
before needed.
If a node does not have an update channel, it is probably not connected,
clarify the log messages and make sure we dont print that it was updated
successfully (continue, not return)
Golangs built in HTTP server does not allow different HTTP timeout for
different types of handlers, so we cannot have a write timeout as we
attempt to do long polling (my bad).
See linked article.
Also removed redundant server declaration
This commit adds initial integration tests for shared nodes, it adds
them and verifies that they are shared.
It does not yet manage to ping the shared node because it does not seem
to establish the connection.
This code adds new http handlers that will generate iOS and macOS
configuration profiles allowing us to override the Control server of the
official Tailscale.app.
Currently, macOS is working, as I have not found the correct "key" to
inject for iOS.
This means that a profile will allow users to no longer log in via the
command line, but they can use the app.
We are currently holding Machine objects in memory for a long time,
while waiting for stream/longpoll, this might make us end up with stale
objects, that we just call save on, potentially overwriting stuff in
the database.
A typical scenario would be someone changing something from the CLI,
e.g. enabling routes, which in turn is overwritten again by the stale
object in the longpolling function.
The code has been left with TODO's and a discussion is available in #93.
This commit splits the lint and test steps into two different jobs in
github actions.
Consider this a suggestion, the idea is that when we look at PRs we will
see explicitly which one of the two types of checks fails without having
to open Github actions.
This commit rewrites the `routes list` command to use ptables to present
a slightly nicer list, including a new field if the route is enabled or
not (which is quite useful).
In addition, it reworks the enable command to support enabling multiple
routes (not only one route as per removed TODO). This allows users to
actually take advantage of exit-nodes and subnet relays.
This commit tries to address the possible raceondition that can happen
if a client closes its connection after we have fetched it from the
syncmap before sending the message.
To try to avoid introducing new dead lock conditions, all messages sent
to updateChannel has been moved into a function, which handles the
locking (instead of calling it all over the place)
The same lock is used around the delete/close function.
This function migrates more poll functions (including keepalive) to
poll.go to keep it somehow in the same file.
In addition it makes changes to improve the stability and ensure nodes
get the appropriate updates from the headscale control and are not left
in an inconsistent state.
Two new additions is:
omitpeers=true will now trigger an update if the clients are not already up
to date
keepalive has been extended with a timer that will check every 120s if
all nodes are up to date.
This commit makes two reasonably major changes:
Set a default timeout for the go HTTP server (which gin uses), which
allows us to actually have broken long poll sessions fail so we can have
the client re-establish them.
The current 10s number is chosen randomly and we need more testing to
ensure that the feature work as intended.
The second is adding a last updated field to keep track of the last time
we had an update that needs to be propagated to all of our
clients/nodes. This will be used to keep track of our machines and if
they are up to date or need us to push an update.
This commit adds a new field to machine, lastSuccessfulUpdate which
tracks when we last was able to send a proper mapupdate to the node. The
purpose of this is to be able to compare to a "global" last updated time
and determine if we need to send an update map request to a node.
In addition it allows us to create a scheduled check to see if all known
nodes are up to date.
Also, add a helper function to send a message to the update channel of a
machine.
This commit adds integration tests to headscale. They are currently
quite simple, but it lays the groundwork for more comprehensive testing
and ensuring we dont break things with the official tailscale client.
The test works by leveraging Docker (via dockertest) to spin up a
Headscale container, and a number of tailscale containers (10).
Each tailscale container is joined to the headscale and then "passed on"
to the tests.
Currently three tests have been implemented:
- Have all tailscale containers join headscale (in the setup process)
- Get IP from each container (I plan to extend this with cross-ping)
- List nodes with headscales CLI and verify all has been registered
This test depends on Docker, and currently, I have not looked into
hooking it into Github Actions.
This commit makes several changes to the dockerfile:
- Add go.mod and go.sum in a seperate stage, subsequently calling `go
mod download` to make it cache dependencies and speed up builds
- Use ubuntu:latest (28MB larger) instead of scratch, makes the image a
lot easier to debug (e.g. it has a shell and a package manager)
- Change ENTRYPOINT to CMD, this makes the behaviour of the image
slightly different from a CLI perspective, but makes interacting with
the image from code, docker-compose and kubernetes easier.
This is based on the premis that "the user know what command they
executed" and therefor know that the output is the key.
This makes the command a lot more useful in scripts.
This commit tries to detect if users can render colors in their terminal
and only enables color logs if that is true.
It also adds no-color.org's NO_COLOR env var support to allow it to be
disabled.
This commit removes most of the locks in the PollingMap handler as there
was combinations that caused deadlocks. Instead of doing a plain map and
doing the locking ourselves, we use sync.Map which handles it for us.
This commit reworks getAvailableIp with a "simpler" version that will
look for the first available IP address in our IP Prefix.
There is a couple of ideas behind this:
* Make the host IPs reasonably predictable and in within similar
subnets, which should simplify ACLs for subnets
* The code is not random, but deterministic so we can have tests
* The code is a bit more understandable (no bit shift magic)
This commit makes the IP prefix used to generate addresses configurable
to users. This can be useful if you would like to use a smaller range or
if your current setup is overlapping with the current range.
The current range is left as a default
Currently the default (and non-configurable) Let's Encrypt listener will
bind to all IPs. This isn't ideal if we want to run headscale on a specific
IP only.
This also allows for one to set the listener to something other than
port 80. This is useful for OSs like OpenBSD which only allow root to
bind the lower port ranges (and don't have `setcap`) as we can now run
`headscale` as a non-privileged user while still using the baked in ACME
magic. Obviously this configuration would also require a reverse proxy
or firewall rule to redirect traffic. I attempted to outline that in the
README change.
tests for that feature.
Other fixes: clean up a few typos in comments. Fix a bug that caused the
tests to run four times each. Be more consistent in the use of log
rather than fmt to print errors and notices.
The issue was that our build pipeline uses 'go get' call to install
golint, which changed the go.mod/go.sum files (not good, but I hadn't
noticed before). Due to Golang bug #44129, this caused breakage on the
dependencies of certain modules we use.
The fix was to switch to 'go install golang.org/x/lint/golint@latest'.
The addition of '@latest' puts 'go install' in module aware mode, which
no longer changes go.mod file in the current directory. This is better,
and it also avoids bug #44129.
This commit also has a change due to `go mod tidy`. Finally, I had to
add a longer timeout for the golangci-lint installation step in the
github actions workflow, since that seems to take a bit over a minute
now. This step is usually cached on subsequent runs, so we hadn't seen
that failure before.
value from CreatePreAuthKey and GetPreAuthKeys. Add tests for that bug,
and the rest of the preauthkeys functionality.
Fix path in `compress` Makefile target.
target calls the new version-at-commit.sh script which will
automatically populate the version variable inside the Headscale binary.
Once we start tagging releases on the git tree, that will come in handy.
The Makefile also has a 'test' target (does nothing yet, no tests yet)
and a 'dev' target, which runs linters, tests, and finally builds.
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.da=function(){this.pipeline.reset(),this.pipeline.add(e.da.trimmer,e.da.stopWordFilter,e.da.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.da.stemmer))},e.da.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.da.trimmer=e.trimmerSupport.generateTrimmer(e.da.wordCharacters),e.Pipeline.registerFunction(e.da.trimmer,"trimmer-da"),e.da.stemmer=function(){varr=e.stemmerSupport.Among,i=e.stemmerSupport.SnowballProgram,n=newfunction(){functione(){vare,r=f.cursor+3;if(d=f.limit,0<=r&&r<=f.limit){for(a=r;;){if(e=f.cursor,f.in_grouping(w,97,248)){f.cursor=e;break}if(f.cursor=e,e>=f.limit)return;f.cursor++}for(;!f.out_grouping(w,97,248);){if(f.cursor>=f.limit)return;f.cursor++}d=f.cursor,d<a&&(d=a)}}functionn(){vare,r;if(f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(c,32),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case1:f.slice_del();break;case2:f.in_grouping_b(p,97,229)&&f.slice_del()}}functiont(){vare,r=f.limit-f.cursor;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.find_among_b(l,4)?(f.bra=f.cursor,f.limit_backward=e,f.cursor=f.limit-r,f.cursor>f.limit_backward&&(f.cursor--,f.bra=f.cursor,f.slice_del())):f.limit_backward=e)}functions(){vare,r,i,n=f.limit-f.cursor;if(f.ket=f.cursor,f.eq_s_b(2,"st")&&(f.bra=f.cursor,f.eq_s_b(2,"ig")&&f.slice_del()),f.cursor=f.limit-n,f.cursor>=d&&(r=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,e=f.find_among_b(m,5),f.limit_backward=r,e))switch(f.bra=f.cursor,e){case1:f.slice_del(),i=f.limit-f.cursor,t(),f.cursor=f.limit-i;break;case2:f.slice_from("løs")}}functiono(){vare;f.cursor>=d&&(e=f.limit_backward,f.limit_backward=d,f.ket=f.cursor,f.out_grouping_b(w,97,248)?(f.bra=f.cursor,u=f.slice_to(u),f.limit_backward=e,f.eq_v_b(u)&&f.slice_del()):f.limit_backward=e)}vara,d,u,c=[newr("hed",-1,1),newr("ethed",0,1),newr("ered",-1,1),newr("e",-1,1),newr("erede",3,1),newr("ende",3,1),newr("erende",5,1),newr("ene",3,1),newr("erne",3,1),newr("ere",3,1),newr("en",-1,1),newr("heden",10,1),newr("eren",10,1),newr("er",-1,1),newr("heder",13,1),newr("erer",13,1),newr("s",-1,2),newr("heds",16,1),newr("es",16,1),newr("endes",18,1),newr("erendes",19,1),newr("enes",18,1),newr("ernes",18,1),newr("eres",18,1),newr("ens",16,1),newr("hedens",24,1),newr("erens",24,1),newr("ers",16,1),newr("ets",16,1),newr("erets",28,1),newr("et",-1,1),newr("eret",30,1)],l=[newr("gd",-1,-1),newr("dt",-1,-1),newr("gt",-1,-1),newr("kt",-1,-1)],m=[newr("ig",-1,1),newr("lig",0,1),newr("elig",1,1),newr("els",-1,1),newr("løst",-1,2)],w=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],p=[239,254,42,3,0,0,0,0,0,0,0,0,0,0,0,0,16],f=newi;this.setCurrent=function(e){f.setCurrent(e)},this.getCurrent=function(){returnf.getCurrent()},this.stem=function(){varr=f.cursor;returne(),f.limit_backward=r,f.cursor=f.limit,n(),f.cursor=f.limit,t(),f.cursor=f.limit,s(),f.cursor=f.limit,o(),!0}};returnfunction(e){return"function"==typeofe.update?e.update(function(e){returnn.setCurrent(e),n.stem(),n.getCurrent()}):(n.setCurrent(e),n.stem(),n.getCurrent())}}(),e.Pipeline.registerFunction(e.da.stemmer,"stemmer-da"),e.da.stopWordFilter=e.generateStopWordFilter("ad af alle alt anden at blev blive bliver da de dem den denne der deres det dette dig din disse dog du efter eller en end er et for fra ham han hans har havde have hende hendes her hos hun hvad hvis hvor i ikke ind jeg jer jo kunne man mange med meget men mig min mine mit mod ned noget nogle nu når og også om op os over på selv sig sin sine sit skal skulle som sådan thi til ud under var vi vil ville vor være været".split(" ")),e.Pipeline.registerFunction(e.da.stopWordFilter,"stopWordFilter-da")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){returnfunction(e){return"function"==typeofe.update?e.update(function(e){returne}):e}}();varr=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void0==i)return[];if(Array.isArray(i))returni.map(function(r){returnisLunr2?newe.Token(r.toLowerCase()):r.toLowerCase()});vart=i.toString().toLowerCase().replace(/^\s+/,"");returnr.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){returnfunction(e){return"function"==typeofe.update?e.update(function(e){returne}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.kn=function(){this.pipeline.reset(),this.pipeline.add(e.kn.trimmer,e.kn.stopWordFilter,e.kn.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.kn.stemmer))},e.kn.wordCharacters="ಀ-಄ಅ-ಔಕ-ಹಾ-ೌ಼-ಽೕ-ೖೝ-ೞೠ-ೡೢ-ೣ೦-೯ೱ-ೳ",e.kn.trimmer=e.trimmerSupport.generateTrimmer(e.kn.wordCharacters),e.Pipeline.registerFunction(e.kn.trimmer,"trimmer-kn"),e.kn.stopWordFilter=e.generateStopWordFilter("ಮತ್ತು ಈ ಒಂದು ರಲ್ಲಿ ಹಾಗೂ ಎಂದು ಅಥವಾ ಇದು ರ ಅವರು ಎಂಬ ಮೇಲೆ ಅವರ ತನ್ನ ಆದರೆ ತಮ್ಮ ನಂತರ ಮೂಲಕ ಹೆಚ್ಚು ನ ಆ ಕೆಲವು ಅನೇಕ ಎರಡು ಹಾಗು ಪ್ರಮುಖ ಇದನ್ನು ಇದರ ಸುಮಾರು ಅದರ ಅದು ಮೊದಲ ಬಗ್ಗೆ ನಲ್ಲಿ ರಂದು ಇತರ ಅತ್ಯಂತ ಹೆಚ್ಚಿನ ಸಹ ಸಾಮಾನ್ಯವಾಗಿ ನೇ ಹಲವಾರು ಹೊಸ ದಿ ಕಡಿಮೆ ಯಾವುದೇ ಹೊಂದಿದೆ ದೊಡ್ಡ ಅನ್ನು ಇವರು ಪ್ರಕಾರ ಇದೆ ಮಾತ್ರ ಕೂಡ ಇಲ್ಲಿ ಎಲ್ಲಾ ವಿವಿಧ ಅದನ್ನು ಹಲವು ರಿಂದ ಕೇವಲ ದ ದಕ್ಷಿಣ ಗೆ ಅವನ ಅತಿ ನೆಯ ಬಹಳ ಕೆಲಸ ಎಲ್ಲ ಪ್ರತಿ ಇತ್ಯಾದಿ ಇವು ಬೇರೆ ಹೀಗೆ ನಡುವೆ ಇದಕ್ಕೆ ಎಸ್ ಇವರ ಮೊದಲು ಶ್ರೀ ಮಾಡುವ ಇದರಲ್ಲಿ ರೀತಿಯ ಮಾಡಿದ ಕಾಲ ಅಲ್ಲಿ ಮಾಡಲು ಅದೇ ಈಗ ಅವು ಗಳು ಎ ಎಂಬುದು ಅವನು ಅಂದರೆ ಅವರಿಗೆ ಇರುವ ವಿಶೇಷ ಮುಂದೆ ಅವುಗಳ ಮುಂತಾದ ಮೂಲ ಬಿ ಮೀ ಒಂದೇ ಇನ್ನೂ ಹೆಚ್ಚಾಗಿ ಮಾಡಿ ಅವರನ್ನು ಇದೇ ಯ ರೀತಿಯಲ್ಲಿ ಜೊತೆ ಅದರಲ್ಲಿ ಮಾಡಿದರು ನಡೆದ ಆಗ ಮತ್ತೆ ಪೂರ್ವ ಆತ ಬಂದ ಯಾವ ಒಟ್ಟು ಇತರೆ ಹಿಂದೆ ಪ್ರಮಾಣದ ಗಳನ್ನು ಕುರಿತು ಯು ಆದ್ದರಿಂದ ಅಲ್ಲದೆ ನಗರದ ಮೇಲಿನ ಏಕೆಂದರೆ ರಷ್ಟು ಎಂಬುದನ್ನು ಬಾರಿ ಎಂದರೆ ಹಿಂದಿನ ಆದರೂ ಆದ ಸಂಬಂಧಿಸಿದ ಮತ್ತೊಂದು ಸಿ ಆತನ ".split(" ")),e.kn.stemmer=function(){returnfunction(e){return"function"==typeofe.update?e.update(function(e){returne}):e}}();varr=e.wordcut;r.init(),e.kn.tokenizer=function(t){if(!arguments.length||null==t||void0==t)return[];if(Array.isArray(t))returnt.map(function(r){returnisLunr2?newe.Token(r.toLowerCase()):r.toLowerCase()});varn=t.toString().toLowerCase().replace(/^\s+/,"");returnr.cut(n).split("|")},e.Pipeline.registerFunction(e.kn.stemmer,"stemmer-kn"),e.Pipeline.registerFunction(e.kn.stopWordFilter,"stopWordFilter-kn")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.no=function(){this.pipeline.reset(),this.pipeline.add(e.no.trimmer,e.no.stopWordFilter,e.no.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.no.stemmer))},e.no.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.no.trimmer=e.trimmerSupport.generateTrimmer(e.no.wordCharacters),e.Pipeline.registerFunction(e.no.trimmer,"trimmer-no"),e.no.stemmer=function(){varr=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,i=newfunction(){functione(){vare,r=w.cursor+3;if(a=w.limit,0<=r||r<=w.limit){for(s=r;;){if(e=w.cursor,w.in_grouping(d,97,248)){w.cursor=e;break}if(e>=w.limit)return;w.cursor=e+1}for(;!w.out_grouping(d,97,248);){if(w.cursor>=w.limit)return;w.cursor++}a=w.cursor,a<s&&(a=s)}}functioni(){vare,r,n;if(w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(m,29),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case1:w.slice_del();break;case2:n=w.limit-w.cursor,w.in_grouping_b(c,98,122)?w.slice_del():(w.cursor=w.limit-n,w.eq_s_b(1,"k")&&w.out_grouping_b(d,97,248)&&w.slice_del());break;case3:w.slice_from("er")}}functiont(){vare,r=w.limit-w.cursor;w.cursor>=a&&(e=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,w.find_among_b(u,2)?(w.bra=w.cursor,w.limit_backward=e,w.cursor=w.limit-r,w.cursor>w.limit_backward&&(w.cursor--,w.bra=w.cursor,w.slice_del())):w.limit_backward=e)}functiono(){vare,r;w.cursor>=a&&(r=w.limit_backward,w.limit_backward=a,w.ket=w.cursor,e=w.find_among_b(l,11),e?(w.bra=w.cursor,w.limit_backward=r,1==e&&w.slice_del()):w.limit_backward=r)}vars,a,m=[newr("a",-1,1),newr("e",-1,1),newr("ede",1,1),newr("ande",1,1),newr("ende",1,1),newr("ane",1,1),newr("ene",1,1),newr("hetene",6,1),newr("erte",1,3),newr("en",-1,1),newr("heten",9,1),newr("ar",-1,1),newr("er",-1,1),newr("heter",12,1),newr("s",-1,2),newr("as",14,1),newr("es",14,1),newr("edes",16,1),newr("endes",16,1),newr("enes",16,1),newr("hetenes",19,1),newr("ens",14,1),newr("hetens",21,1),newr("ers",14,1),newr("ets",14,1),newr("et",-1,1),newr("het",25,1),newr("ert",-1,3),newr("ast",-1,1)],u=[newr("dt",-1,-1),newr("vt",-1,-1)],l=[newr("leg",-1,1),newr("eleg",0,1),newr("ig",-1,1),newr("eig",2,1),newr("lig",2,1),newr("elig",4,1),newr("els",-1,1),newr("lov",-1,1),newr("elov",7,1),newr("slov",7,1),newr("hetslov",9,1)],d=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,48,0,128],c=[119,125,149,1],w=newn;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){returnw.getCurrent()},this.stem=function(){varr=w.cursor;returne(),w.limit_backward=r,w.cursor=w.limit,i(),w.cursor=w.limit,t(),w.cursor=w.limit,o(),!0}};returnfunction(e){return"function"==typeofe.update?e.update(function(e){returni.setCurrent(e),i.stem(),i.getCurrent()}):(i.setCurrent(e),i.stem(),i.getCurrent())}}(),e.Pipeline.registerFunction(e.no.stemmer,"stemmer-no"),e.no.stopWordFilter=e.generateStopWordFilter("alle at av bare begge ble blei bli blir blitt både båe da de deg dei deim deira deires dem den denne der dere deres det dette di din disse ditt du dykk dykkar då eg ein eit eitt eller elles en enn er et ett etter for fordi fra før ha hadde han hans har hennar henne hennes her hjå ho hoe honom hoss hossen hun hva hvem hver hvilke hvilken hvis hvor hvordan hvorfor i ikke ikkje ikkje ingen ingi inkje inn inni ja jeg kan kom korleis korso kun kunne kva kvar kvarhelst kven kvi kvifor man mange me med medan meg meget mellom men mi min mine mitt mot mykje ned no noe noen noka noko nokon nokor nokre nå når og også om opp oss over på samme seg selv si si sia sidan siden sin sine sitt sjøl skal skulle slik so som som somme somt så sånn til um upp ut uten var vart varte ved vere verte vi vil ville vore vors vort vår være være vært å".split(" ")),e.Pipeline.registerFunction(e.no.stopWordFilter,"stopWordFilter-no")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){varr=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=newfunction(){functione(){vare,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o<a&&(o=a)}}functiont(){vare,r=w.limit_backward;if(w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case1:w.slice_del();break;case2:w.in_grouping_b(d,98,121)&&w.slice_del()}}functioni(){vare=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}functions(){vare,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case1:w.slice_del();break;case2:w.slice_from("lös");break;case3:w.slice_from("full")}w.limit_backward=r}}vara,o,u=[newr("a",-1,1),newr("arna",0,1),newr("erna",0,1),newr("heterna",2,1),newr("orna",0,1),newr("ad",-1,1),newr("e",-1,1),newr("ade",6,1),newr("ande",6,1),newr("arne",6,1),newr("are",6,1),newr("aste",6,1),newr("en",-1,1),newr("anden",12,1),newr("aren",12,1),newr("heten",12,1),newr("ern",-1,1),newr("ar",-1,1),newr("er",-1,1),newr("heter",18,1),newr("or",-1,1),newr("s",-1,2),newr("as",21,1),newr("arnas",22,1),newr("ernas",22,1),newr("ornas",22,1),newr("es",21,1),newr("ades",26,1),newr("andes",26,1),newr("ens",21,1),newr("arens",29,1),newr("hetens",29,1),newr("erns",21,1),newr("at",-1,1),newr("andet",-1,1),newr("het",-1,1),newr("ast",-1,1)],c=[newr("dd",-1,-1),newr("gd",-1,-1),newr("nn",-1,-1),newr("dt",-1,-1),newr("gt",-1,-1),newr("kt",-1,-1),newr("tt",-1,-1)],m=[newr("ig",-1,1),newr("lig",0,1),newr("els",-1,1),newr("fullt",-1,3),newr("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=newn;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){returnw.getCurrent()},this.stem=function(){varr=w.cursor;returne(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};returnfunction(e){return"function"==typeofe.update?e.update(function(e){returnt.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}});
!function(e,t){"function"==typeofdefine&&define.amd?define(t):"object"==typeofexports?module.exports=t():t()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="-உஊ-ஏஐ-ஙச-ட-னப-யர-ஹ-ிீ-ொ-ௐ---௩௪-௯௰-௹௺-a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){returnfunction(e){return"function"==typeofe.update?e.update(function(e){returne}):e}}();vart=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void0==r)return[];if(Array.isArray(r))returnr.map(function(t){returnisLunr2?newe.Token(t.toLowerCase()):t.toLowerCase()});vari=r.toString().toLowerCase().replace(/^\s+/,"");returnt.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}});
!function(e,t){"function"==typeofdefine&&define.amd?define(t):"object"==typeofexports?module.exports=t():t()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){returnfunction(e){return"function"==typeofe.update?e.update(function(e){returne}):e}}();vart=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void0==r)return[];if(Array.isArray(r))returnr.map(function(t){returnisLunr2?newe.Token(t.toLowerCase()):t.toLowerCase()});vari=r.toString().toLowerCase().replace(/^\s+/,"");returnt.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");varr="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[-]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");vart=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void0==i)return[];if(Array.isArray(i))returni.map(function(t){returnr?newe.Token(t):t});varn=i.toString().replace(/^\s+/,"");returnt.cut(n).split("|")}}});
!function(e,r){"function"==typeofdefine&&define.amd?define(r):"object"==typeofexports?module.exports=r():r()(e.lunr)}(this,function(){returnfunction(e){if(void0===e)thrownewError("Lunr is not present. Please include / require Lunr before this script.");if(void0===e.stemmerSupport)thrownewError("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}});
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.