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(" "))}});
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.