diff --git a/README.md b/README.md index fce55097f9f..b6860841242 100644 --- a/README.md +++ b/README.md @@ -305,7 +305,7 @@ To learn more about the Nightscout API, visit https://YOUR-SITE.com/api-docs/ or * `SHOW_PLUGINS` - enabled plugins that should have their visualizations shown, defaults to all enabled * `SHOW_FORECAST` (`ar2`) - plugin forecasts that should be shown by default, supports space delimited values such as `"ar2 openaps"` * `LANGUAGE` (`en`) - language of Nightscout. If not available english is used - * Currently supported language codes are: bg (Български), cs (Čeština), de (Deutsch), dk (Dansk), el (Ελληνικά), en (English), es (Español), fi (Suomi), fr (Français), he (עברית), hr (Hrvatski), it (Italiano), ko (한국어), nb (Norsk (Bokmål)), nl (Nederlands), pl (Polski), pt (Português (Brasil)), ro (Română), ru (Русский), sk (Slovenčina), sv (Svenska), tr (Turkish), zh_cn (中文(简体)), zh_tw (中文(繁體)) + * Currently supported language codes are: bg (Български), cs (Čeština), de (Deutsch), dk (Dansk), el (Ελληνικά), en (English), es (Español), fi (Suomi), fr (Français), he (עברית), hr (Hrvatski), hu (magyar), it (Italiano), ko (한국어), nb (Norsk (Bokmål)), nl (Nederlands), pl (Polski), pt (Português (Brasil)), ro (Română), ru (Русский), sk (Slovenčina), sv (Svenska), tr (Turkish), zh_cn (中文(简体)), zh_tw (中文(繁體)) * `SCALE_Y` (`log`) - The type of scaling used for the Y axis of the charts system wide. * The default `log` (logarithmic) option will let you see more detail towards the lower range, while still showing the full CGM range. * The `linear` option has equidistant tick marks; the range used is dynamic so that space at the top of chart isn't wasted. diff --git a/app.js b/app.js index c6528819bb9..2a94b1dd3e9 100644 --- a/app.js +++ b/app.js @@ -29,19 +29,7 @@ function create (env, ctx) { const enableCSP = env.secureCsp ? true : false; - console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)'); - const helmet = require('helmet'); - var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains; - var preloadValue = env.secureHstsHeaderPreload; - app.use(helmet({ - hsts: { - maxAge: 31536000 - , includeSubDomains: includeSubDomainsValue - , preload: preloadValue - } - , frameguard: false - , contentSecurityPolicy: enableCSP - })); + let cspPolicy = false; if (enableCSP) { var secureCspReportOnly = env.secureCspReportOnly; @@ -60,7 +48,7 @@ function create (env, ctx) { } } - app.use(helmet.contentSecurityPolicy({ //TODO make NS work without 'unsafe-inline' + cspPolicy = { //TODO make NS work without 'unsafe-inline' directives: { defaultSrc: ["'self'"] , styleSrc: ["'self'", 'https://fonts.googleapis.com/', 'https://fonts.gstatic.com/', "'unsafe-inline'"] @@ -76,7 +64,26 @@ function create (env, ctx) { , frameAncestors: frameAncestors } , reportOnly: secureCspReportOnly - })); + }; + } + + + console.info('Enabled SECURE_HSTS_HEADER (HTTP Strict Transport Security)'); + const helmet = require('helmet'); + var includeSubDomainsValue = env.secureHstsHeaderIncludeSubdomains; + var preloadValue = env.secureHstsHeaderPreload; + app.use(helmet({ + hsts: { + maxAge: 31536000 + , includeSubDomains: includeSubDomainsValue + , preload: preloadValue + } + , frameguard: false + , contentSecurityPolicy: cspPolicy + })); + + if (enableCSP) { + app.use(helmet.referrerPolicy({ policy: 'no-referrer' })); app.use(bodyParser.json({ type: ['json', 'application/csp-report'] })); app.post('/report-violation', (req, res) => { @@ -276,9 +283,12 @@ function create (env, ctx) { // API docs const swaggerUi = require('swagger-ui-express'); + const swaggerUseSchema = schema => (...args) => swaggerUi.setup(schema)(...args); const swaggerDocument = require('./swagger.json'); + const swaggerDocumentApiV3 = require('./lib/api3/swagger.json'); - app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument)); + app.use('/api-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocument)); + app.use('/api3-docs', swaggerUi.serve, swaggerUseSchema(swaggerDocumentApiV3)); app.use('/swagger-ui-dist', (req, res) => { res.redirect(307, '/api-docs'); diff --git a/docs/plugins/add-virtual-assistant-support-to-plugin.md b/docs/plugins/add-virtual-assistant-support-to-plugin.md index 60ac1d1957b..6c581013b9e 100644 --- a/docs/plugins/add-virtual-assistant-support-to-plugin.md +++ b/docs/plugins/add-virtual-assistant-support-to-plugin.md @@ -36,9 +36,8 @@ There are 2 types of handlers that you can supply: A plugin can expose multiple intent handlers (e.g. useful when it can supply multiple kinds of metrics). Each intent handler should be structured as follows: + `intent` - This is the intent this handler is built for. Right now, the templates used by both Alexa and Google Home use only the `"MetricNow"` intent (used for getting the present value of the requested metric) -+ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Make sure to add the metric name and its synonyms to the list of metrics used by the virtual assistant(s). - - **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique! - - Note: Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility. ++ `metrics` - An array of metric name(s) the handler will supply. e.g. "What is my `metric`" - iob, bg, cob, etc. Although this value *is* an array, you really should only supply one (unique) value, and then add aliases or synonyms to that value in the list of metrics for the virtual assistant. We keep this value as an array for backwards compatibility. + - **IMPORTANT NOTE:** There is no protection against overlapping metric names, so PLEASE make sure your metric name is unique! + `intenthandler` - This is a callback function that receives 3 arguments: - `callback` Call this at the end of your function. It requires 2 arguments: - `title` - Title of the handler. This is the value that will be displayed on the Alexa card (for devices with a screen). The Google Home response doesn't currently display a card, so it doesn't use this value. diff --git a/docs/plugins/alexa-templates/en-us.json b/docs/plugins/alexa-templates/en-us.json index 79cc1baa977..20bf8c290d1 100644 --- a/docs/plugins/alexa-templates/en-us.json +++ b/docs/plugins/alexa-templates/en-us.json @@ -68,6 +68,14 @@ { "name": "AMAZON.StopIntent", "samples": [] + }, + { + "name": "AMAZON.CancelIntent", + "samples": [] + }, + { + "name": "AMAZON.HelpIntent", + "samples": [] } ], "types": [ @@ -233,6 +241,16 @@ "name": { "value": "cgm mode" } + }, + { + "name": { + "value": "db size", + "synonyms": [ + "database size", + "data size", + "file size" + ] + } } ] } diff --git a/docs/plugins/google-home-templates/en-us.zip b/docs/plugins/google-home-templates/en-us.zip index d8ada2a834a..551e51307f0 100644 Binary files a/docs/plugins/google-home-templates/en-us.zip and b/docs/plugins/google-home-templates/en-us.zip differ diff --git a/docs/plugins/googlehome-plugin.md b/docs/plugins/googlehome-plugin.md index 5b82bdfb053..fc76117059e 100644 --- a/docs/plugins/googlehome-plugin.md +++ b/docs/plugins/googlehome-plugin.md @@ -41,7 +41,8 @@ To add Google Home support for your Nightscout site, here's what you need to do: 1. Click on the "New Project" button. 1. If prompted, agree to the Terms of Service. 1. Give your project a name (e.g. "Nightscout") and then click "Create project". -1. For the "development experience", select "Conversational" at the bottom of the list. +1. When asked what kind of Action you want to build, select "Custom" and then click the "Next" button. +1. When selecting how you want to build the project, scroll down to the bottom of the screen and click the link to build it using DialogFlow. 1. Click on the "Develop" tab at the top of the sreen. 1. Click on "Invocation" in the left navigation pane. 1. Set the display name (e.g. "Night Scout") of your Action and set your Google Assistant voice. diff --git a/lib/api/alexa/index.js b/lib/api/alexa/index.js index 2a5fd4ef6cd..3c31bf1ce00 100644 --- a/lib/api/alexa/index.js +++ b/lib/api/alexa/index.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var moment = require('moment'); function configure (app, wares, ctx, env) { @@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) { api.post('/alexa', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { console.log('Incoming request from Alexa'); - var locale = req.body.request.locale; + var locale = _.get(req, 'body.request.locale'); if(locale){ if(locale.length > 2) { locale = locale.substr(0, 2); @@ -78,19 +79,10 @@ function configure (app, wares, ctx, env) { function handleIntent(intentName, slots, next) { var metric; if (slots) { - if (slots.metric - && slots.metric.resolutions - && slots.metric.resolutions.resolutionsPerAuthority - && slots.metric.resolutions.resolutionsPerAuthority.length - && slots.metric.resolutions.resolutionsPerAuthority[0].status - && slots.metric.resolutions.resolutionsPerAuthority[0].status.code - && slots.metric.resolutions.resolutionsPerAuthority[0].status.code == "ER_SUCCESS_MATCH" - && slots.metric.resolutions.resolutionsPerAuthority[0].values - && slots.metric.resolutions.resolutionsPerAuthority[0].values.length - && slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value - && slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name - ){ - metric = slots.metric.resolutions.resolutionsPerAuthority[0].values[0].value.name; + var slotStatus = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].status.code'); + var slotName = _.get(slots, 'metric.resolutions.resolutionsPerAuthority[0].values[0].value.name'); + if (slotStatus == "ER_SUCCESS_MATCH" && slotName) { + metric = slotName; } else { next(translate('virtAsstUnknownIntentTitle'), translate('virtAsstUnknownIntentText')); return; diff --git a/lib/api/googlehome/index.js b/lib/api/googlehome/index.js index b44715b25eb..cd42aa0ff37 100644 --- a/lib/api/googlehome/index.js +++ b/lib/api/googlehome/index.js @@ -1,5 +1,6 @@ 'use strict'; +var _ = require('lodash'); var moment = require('moment'); function configure (app, wares, ctx, env) { @@ -18,7 +19,7 @@ function configure (app, wares, ctx, env) { api.post('/googlehome', ctx.authorization.isPermitted('api:*:read'), function (req, res, next) { console.log('Incoming request from Google Home'); - var locale = req.body.queryResult.languageCode; + var locale = _.get(req, 'body.queryResult.languageCode'); if(locale){ if(locale.length > 2) { locale = locale.substr(0, 2); diff --git a/lib/api/status.js b/lib/api/status.js index b630d629593..56196114a07 100644 --- a/lib/api/status.js +++ b/lib/api/status.js @@ -32,6 +32,7 @@ function configure (app, wares, env, ctx) { , settings: settings , extendedSettings: extended , authorized: ctx.authorization.authorize(authToken) + , runtimeState: ctx.runtimeState }; var badge = 'http://img.shields.io/badge/Nightscout-OK-green'; diff --git a/lib/api3/doc/tutorial.md b/lib/api3/doc/tutorial.md index 3d8c656dfbd..d69e95ef4a4 100644 --- a/lib/api3/doc/tutorial.md +++ b/lib/api3/doc/tutorial.md @@ -11,7 +11,7 @@ Each NS instance with API v3 contains self-included OpenAPI specification at [/a --- ### VERSION -[VERSION](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/other/get_version) operation gets you basic information about software packages versions. +[VERSION](https://nsapiv3.herokuapp.com/api3-docs/#/other/get_version) operation gets you basic information about software packages versions. It is public (there is no need to add authorization parameters/headers). Sample GET `/version` client code (to get actual versions): @@ -38,7 +38,7 @@ Sample result: --- ### STATUS -[STATUS](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/other/get_status) operation gets you basic information about software packages versions. +[STATUS](https://nsapiv3.herokuapp.com/api3-docs/#/other/get_status) operation gets you basic information about software packages versions. It is public (there is no need to add authorization parameters/headers). Sample GET `/status` client code (to get my actual permissions): @@ -75,7 +75,7 @@ Sample result: --- ### SEARCH -[SEARCH](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/SEARCH) operation filters, sorts, paginates and projects documents from the collection. +[SEARCH](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/SEARCH) operation filters, sorts, paginates and projects documents from the collection. Sample GET `/entries` client code (to retrieve last 3 BG values): ```javascript @@ -110,7 +110,7 @@ Sample result: --- ### CREATE -[CREATE](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/generic/post__collection_) operation inserts a new document into the collection. +[CREATE](https://nsapiv3.herokuapp.com/api3-docs/#/generic/post__collection_) operation inserts a new document into the collection. Sample POST `/treatments` client code: ```javascript @@ -140,7 +140,7 @@ Sample result: --- ### READ -[READ](https://nsapiv3.herokuapp.com/api/v3/swagger-ui-dist/#/generic/get__collection___identifier_) operation retrieves you a single document from the collection by its identifier. +[READ](https://nsapiv3.herokuapp.com/api3-docs/#/generic/get__collection___identifier_) operation retrieves you a single document from the collection by its identifier. Sample GET `/treatments/{identifier}` client code: ```javascript @@ -172,7 +172,7 @@ Sample result: --- ### LAST MODIFIED -[LAST MODIFIED](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/other/LAST-MODIFIED) operation finds the date of last modification for each collection. +[LAST MODIFIED](https://nsapiv3insecure.herokuapp.com/api3-docs/#/other/LAST-MODIFIED) operation finds the date of last modification for each collection. Sample GET `/lastModified` client code (to get latest modification dates): ```javascript @@ -199,7 +199,7 @@ Sample result: --- ### UPDATE -[UPDATE](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/put__collection___identifier_) operation updates existing document in the collection. +[UPDATE](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/put__collection___identifier_) operation updates existing document in the collection. Sample PUT `/treatments/{identifier}` client code (to update `insulin` from 0.3 to 0.4): ```javascript @@ -231,7 +231,7 @@ Sample result: --- ### PATCH -[PATCH](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/patch__collection___identifier_) operation partially updates existing document in the collection. +[PATCH](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/patch__collection___identifier_) operation partially updates existing document in the collection. Sample PATCH `/treatments/{identifier}` client code (to update `insulin` from 0.4 to 0.5): ```javascript @@ -259,7 +259,7 @@ Sample result: --- ### DELETE -[DELETE](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/delete__collection___identifier_) operation deletes existing document from the collection. +[DELETE](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/delete__collection___identifier_) operation deletes existing document from the collection. Sample DELETE `/treatments/{identifier}` client code (to update `insulin` from 0.4 to 0.5): ```javascript @@ -282,7 +282,7 @@ Sample result: --- ### HISTORY -[HISTORY](https://nsapiv3insecure.herokuapp.com/api/v3/swagger-ui-dist/index.html#/generic/HISTORY2) operation queries all changes since the timestamp. +[HISTORY](https://nsapiv3insecure.herokuapp.com/api3-docs/#/generic/HISTORY2) operation queries all changes since the timestamp. Sample HISTORY `/treatments/history/{lastModified}` client code: ```javascript @@ -326,4 +326,4 @@ Sample result: } ] ``` -Notice the `"isValid":false` field marking the deletion of the document. \ No newline at end of file +Notice the `"isValid":false` field marking the deletion of the document. diff --git a/lib/api3/index.js b/lib/api3/index.js index 4bfe07a35fe..bff0899536f 100644 --- a/lib/api3/index.js +++ b/lib/api3/index.js @@ -7,7 +7,6 @@ const express = require('express') , apiConst = require('./const.json') , security = require('./security') , genericSetup = require('./generic/setup') - , swaggerSetup = require('./swagger') ; function configure (env, ctx) { @@ -35,7 +34,7 @@ function configure (env, ctx) { self.setupApiEnvironment = function setupApiEnvironment () { - + app.use(bodyParser.json({ limit: 1048576 * 50 }), function errorHandler (err, req, res, next) { @@ -100,7 +99,10 @@ function configure (env, ctx) { self.setupApiEnvironment(); genericSetup(ctx, env, app); self.setupApiRoutes(); - swaggerSetup(app); + + app.use('/swagger-ui-dist', (req, res) => { + res.redirect(307, '../../../api3-docs'); + }); ctx.storageSocket = new StorageSocket(app, env, ctx); diff --git a/lib/api3/swagger.js b/lib/api3/swagger.js deleted file mode 100644 index ff965061c87..00000000000 --- a/lib/api3/swagger.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -const express = require('express') - , fs = require('fs') - ; - - -function setupSwaggerUI (app) { - - const serveSwaggerDef = function serveSwaggerDef (req, res) { - res.sendFile(__dirname + '/swagger.yaml'); - }; - app.get('/swagger', serveSwaggerDef); - - const swaggerUiAssetPath = require('swagger-ui-dist').getAbsoluteFSPath(); - const swaggerFiles = express.static(swaggerUiAssetPath); - - const urlRegex = /url: "[^"]*",/; - - const patchIndex = function patchIndex (req, res) { - const indexContent = fs.readFileSync(`${swaggerUiAssetPath}/index.html`) - .toString() - .replace(urlRegex, 'url: "../swagger.yaml",'); - res.send(indexContent); - }; - - app.get('/swagger-ui-dist', function getSwaggerRoot (req, res) { - let targetUrl = req.originalUrl; - if (!targetUrl.endsWith('/')) { - targetUrl += '/'; - } - targetUrl += 'index.html'; - res.redirect(targetUrl); - }); - app.get('/swagger-ui-dist/index.html', patchIndex); - - app.use('/swagger-ui-dist', swaggerFiles); -} - - -module.exports = setupSwaggerUI; \ No newline at end of file diff --git a/lib/api3/swagger.json b/lib/api3/swagger.json new file mode 100644 index 00000000000..b20bb0e6761 --- /dev/null +++ b/lib/api3/swagger.json @@ -0,0 +1,2251 @@ +{ + "openapi": "3.0.0", + "info": { + "title": "Nightscout API", + "description": "Nightscout API v3 is a component of cgm-remote-monitor project. It aims to provide lightweight, secured and HTTP REST compliant interface for your T1D treatment data exchange.\n\nAPI v3 uses these environment variables, among other things:\n- Security switch (optional, default = `true`)
API3_SECURITY_ENABLE=true
You can turn the whole security mechanism off, e.g. for debugging or development purposes, but this should never be set to false in production.\n\n- Number of minutes of acceptable time skew between client's and server's clock (optional, default = 5)
API3_TIME_SKEW_TOLERANCE=5
This security parameter is used for preventing anti-replay attacks, specifically when checking the time from `Date` header.\n\n- Maximum limit count of documents retrieved from single query
API3_MAX_LIMIT=1000
\n\n- Autopruning of obsolete documents (optional, default is only `DEVICESTATUS`=60)
API3_AUTOPRUNE_DEVICESTATUS=60\nAPI3_AUTOPRUNE_ENTRIES=365\nAPI3_AUTOPRUNE_TREATMENTS=120 
You can specify for which collections autopruning will be activated and length of retention period in days, e.g. \"Hold 60 days of devicestatus, automatically delete older documents, hold 365 days of treatments and entries, automatically delete older documents.\"\n\n- Fallback deduplication switch (optional, default = true)
API3_DEDUP_FALLBACK_ENABLED=true
API3 uses the `identifier` field for document identification and mutual distinction within a single collection. There is automatic deduplication implemented matching the equal `identifier` field. E.g. `CREATE` operation for document having the same `identifier` as another one existing in the database is automatically transformed into `UPDATE` operation of the document found in the database.\nDocuments not created via API v3 usually does not have any `identifier` field, but we would like to have some form of deduplication for them, too. This fallback deduplication is turned on by having set `API3_DEDUP_FALLBACK_ENABLED` to `true`. When searching the collection in database, the document is found to be a duplicate only when either he has equal `identifier` or he has no `identifier` and meets:
`devicestatus` collection: equal combination of `created_at` and `device`\n`entries` collection:      equal combination of `date` and `type`\n`food` collection:         equal `created_at`\n`profile` collection:      equal `created_at`\n`treatments` collection:   equal combination of `created_at` and `eventType` 
\n\n- Fallback switch for adding `created_at` field along the `date` field (optional, default = true)
API3_CREATED_AT_FALLBACK_ENABLED=true
Standard APIv3 document model uses only `date` field for storing a timestamp of the event recorded by the document. But there is a fallback option to fill `created_at` field as well automatically on each insert/update, just to keep all older components working.", + "contact": { + "name": "NS development discussion channel", + "url": "https://gitter.im/nightscout/public" + }, + "license": { + "name": "AGPL 3", + "url": "https://www.gnu.org/licenses/agpl.txt" + }, + "version": "3.0.1" + }, + "servers": [ + { + "url": "/api/v3" + } + ], + "tags": [ + { + "name": "generic", + "description": "Generic operations with each database collection (devicestatus, entries, food, profile, settings, treatments)" + }, + { + "name": "other", + "description": "All other various operations" + } + ], + "paths": { + "/{collection}": { + "get": { + "tags": [ + "generic" + ], + "summary": "SEARCH: Search documents from the collection", + "description": "General search operation through documents of one collection, matching the specified filtering criteria. You can apply:\n\n1) filtering - combining any number of filtering parameters\n\n2) ordering - using `sort` or `sort$desc` parameter\n\n3) paging - using `limit` and `skip` parameters\n\nWhen there is no document matching the filtering criteria, HTTP status 204 is returned with empty response content. Otherwise HTTP 200 code is returned with JSON array of matching documents as a response content.\n\nThis operation requires `read` permission for the API and the collection (e.g. `*:*:read`, `api:*:read`, `*:treatments:read`, `api:treatments:read`).\n\nThe only exception is the `settings` collection which requires `admin` permission (`api:settings:admin`), because the settings of each application should be isolated and kept secret. You need to know the concrete identifier to access the app's settings.", + "operationId": "SEARCH", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "filter_parameters", + "in": "query", + "description": "Any number of filtering operators.\n\nEach filtering operator has name like `$`, e.g. `carbs$gt=2` which represents filtering rule \"The field carbs must be present and greater than 2\".\n\nYou can choose from operators:\n\n`eq`=equals, `insulin$eq=1.5`\n\n`ne`=not equals, `insulin$ne=1.5`\n\n`gt`=greater than, `carbs$gt=30`\n\n`gte`=greater than or equal, `carbs$gte=30`\n\n`lt`=less than, `carbs$lt=30`\n\n`lte`=less than or equal, `carbs$lte=30`\n\n`in`=in specified set, `type$in=sgv|mbg|cal`\n\n`nin`=not in specified set, `eventType$nin=Temp%20Basal|Temporary%20Target`\n\n`re`=regex pattern, `eventType$re=Temp.%2A`\n\nWhen filtering by field `date`, `created_at`, `srvModified` or `srvCreated`, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always queried in a normalized form - UTC with zero offset and with the correct format (1525383610088 for `date`, '2018-05-03T21:40:10.088Z' for `created_at`).", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "sort", + "in": "query", + "description": "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "sort$desc", + "in": "query", + "description": "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of documents to get in result array", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 1, + "type": "integer", + "example": 100 + } + }, + { + "name": "skip", + "in": "query", + "description": "Number of documents to skip from collection query before loading them into result array (used for pagination)", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 0, + "type": "integer", + "example": 0, + "default": 0 + } + }, + { + "name": "fields", + "in": "query", + "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string", + "default": "_all" + }, + "examples": { + "all": { + "summary": "All fields will be returned (default behaviour)", + "value": "_all" + }, + "customSet": { + "summary": "Only fields date and insulin will be returned", + "value": "date,insulin" + } + } + } + ], + "responses": { + "200": { + "description": "Successful operation returning array of documents matching the filtering criteria", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + } + } + }, + "204": { + "description": "Successful operation - no documents matching the filtering criteria" + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "406": { + "description": "The requested content type (in `Accept` header) is not supported." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + }, + "post": { + "tags": [ + "generic" + ], + "summary": "CREATE: Inserts a new document into the collection", + "description": "Using this operation you can insert new documents into collection. Normally the operation ends with 201 HTTP status code, `Last-Modified` and `Location` headers specified and with an empty response content. `identifier` can be parsed from the `Location` response header.\n\nWhen the document to post is marked as a duplicate (using rules described at `API3_DEDUP_FALLBACK_ENABLED` switch), the update operation takes place instead of inserting. In this case the original document in the collection is found and it gets updated by the actual operation POST body. Finally the operation ends with 204 HTTP status code along with `Last-Modified` and correct `Location` headers.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `create` (and/or `update` for deduplication) permission for the API and the collection (e.g. `api:treatments:create` and `api:treatments:update`)", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "JSON with new document to insert", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentToPost" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created a new document in collection", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "204": { + "description": "Successfully finished operation", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "422": { + "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/{collection}/{identifier}": { + "get": { + "tags": [ + "generic" + ], + "summary": "READ: Retrieves a single document from the collection", + "description": "Basically this operation looks for a document matching the `identifier` field returning 200 or 404 HTTP status code.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen `If-Modified-Since` header is used and its value is greater than the timestamp of the document in the collection, 304 HTTP status code with empty response content is returned. It means that the document has not been modified on server since the last retrieval to client side. With `If-Modified-Since` header and less or equal timestamp `srvModified` a normal 200 HTTP status with full response is returned.\n\nThis operation requires `read` permission for the API and the collection (e.g. `api:treatments:read`)", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "identifier", + "in": "path", + "description": "Identifier of the document to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramIdentifier" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "If-Modified-Since", + "in": "header", + "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Modified-Since: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "fields", + "in": "query", + "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string", + "default": "_all" + }, + "examples": { + "all": { + "summary": "All fields will be returned (default behaviour)", + "value": "_all" + }, + "customSet": { + "summary": "Only fields date and insulin will be returned", + "value": "date,insulin" + } + } + } + ], + "responses": { + "200": { + "description": "The document has been succesfully found and its JSON form returned in the response content.", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Document" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/Document" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Document" + } + } + } + }, + "304": { + "description": "The document has not been modified on the server since timestamp specified in If-Modified-Since header", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + } + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "406": { + "description": "The requested content type (in `Accept` header) is not supported." + }, + "410": { + "description": "The requested document has already been deleted." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + }, + "put": { + "tags": [ + "generic" + ], + "summary": "UPDATE: Updates a document in the collection", + "description": "Normally the document with the matching `identifier` will be replaced in the collection by the whole JSON request body and 204 HTTP status code will be returned with empty response body.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen no document with `identifier` has been found in the collection, then an insert operation takes place instead of updating. Finally 201 HTTP status code is returned with only `Last-Modified` header (`identifier` is already known from the path parameter).\n\nYou can also specify `If-Unmodified-Since` request header including your timestamp of document's last modification. If the document has been modified by somebody else on the server afterwards (and you do not know about it), the 412 HTTP status code is returned cancelling the update operation. You can use this feature to prevent race condition problems.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `update` (and/or `create`) permission for the API and the collection (e.g. `api:treatments:update` and `api:treatments:create`)", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "identifier", + "in": "path", + "description": "Identifier of the document to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramIdentifier" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "If-Unmodified-Since", + "in": "header", + "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "JSON of new version of document (`identifier` in JSON is ignored if present)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentToPost" + } + } + }, + "required": true + }, + "responses": { + "201": { + "description": "Successfully created a new document in collection", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + } + }, + "204": { + "description": "Successfully finished operation", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "410": { + "description": "The requested document has already been deleted." + }, + "412": { + "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)." + }, + "422": { + "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + }, + "delete": { + "tags": [ + "generic" + ], + "summary": "DELETE: Deletes a document from the collection", + "description": "If the document has already been deleted, the operation will succeed anyway. Normally, documents are not really deleted from the collection but they are only marked as deleted. For special cases the deletion can be irreversible using `permanent` parameter.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `delete` permission for the API and the collection (e.g. `api:treatments:delete`)", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "identifier", + "in": "path", + "description": "Identifier of the document to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramIdentifier" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "permanent", + "in": "query", + "description": "If true, the deletion will be irreversible and it will not appear in `HISTORY` operation. Normally there is no reason for setting this flag.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "204": { + "description": "Successful operation - empty response" + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "422": { + "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + }, + "patch": { + "tags": [ + "generic" + ], + "summary": "PATCH: Partially updates document in the collection", + "description": "Normally the document with the matching `identifier` will be retrieved from the collection and it will be patched by all specified fields from the JSON request body. Finally 204 HTTP status code will be returned with empty response body.\n\nIf the document has been found in the collection but it had already been deleted, 410 HTTP status code with empty response content is to be returned.\n\nWhen no document with `identifier` has been found in the collection, then the operation ends with 404 HTTP status code.\n\nYou can also specify `If-Unmodified-Since` request header including your timestamp of document's last modification. If the document has been modified by somebody else on the server afterwards (and you do not know about it), the 412 HTTP status code is returned cancelling the update operation. You can use this feature to prevent race condition problems.\n\n`PATCH` operation can save some bandwidth for incremental document updates in comparison with `GET` - `UPDATE` operation sequence.\n\nWhile patching the document, the field `modifiedBy` is automatically set to the authorized subject's name.\n\nThis operation provides autopruning of the collection (if autopruning is enabled).\n\nThis operation requires `update` permission for the API and the collection (e.g. `api:treatments:update`)", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "identifier", + "in": "path", + "description": "Identifier of the document to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramIdentifier" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "If-Unmodified-Since", + "in": "header", + "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "description": "JSON of new version of document (`identifier` in JSON is ignored if present)", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentToPost" + } + } + }, + "required": true + }, + "responses": { + "204": { + "description": "Successfully finished operation", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "410": { + "description": "The requested document has already been deleted." + }, + "412": { + "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)." + }, + "422": { + "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/{collection}/history": { + "get": { + "tags": [ + "generic" + ], + "summary": "HISTORY: Retrieves incremental changes since timestamp", + "description": "HISTORY operation is intended for continuous data synchronization with other systems.\nEvery insertion, update and deletion will be included in the resulting JSON array of documents (since timestamp in `Last-Modified` request header value). All changes are listed chronologically in response with 200 HTTP status code. The maximum listed `srvModified` timestamp is also stored in `Last-Modified` and `ETag` response headers that you can use for future, directly following synchronization. You can also limit the array's length using `limit` parameter.\n\nDeleted documents will appear with `isValid` = `false` field.\n\nWhen there is no change detected since the timestamp the operation ends with 204 HTTP status code and empty response content.\n\nHISTORY operation has a fallback mechanism in place for documents, which were not created by API v3. For such documents `srvModified` is virtually assigned from the `date` field (for `entries` collection) or from the `created_at` field (for other collections).\n\nThis operation requires `read` permission for the API and the collection (e.g. `api:treatments:read`)\n\nThe only exception is the `settings` collection which requires `admin` permission (`api:settings:admin`), because the settings of each application should be isolated and kept secret. You need to know the concrete identifier to access the app's settings.", + "operationId": "HISTORY", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "Last-Modified", + "in": "header", + "description": "Starting timestamp (defined with respect to server's clock) since which the changes in documents are to be listed, formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nExample:\n\n
Last-Modified: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of documents to get in result array", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 1, + "type": "integer", + "example": 100 + } + }, + { + "name": "fields", + "in": "query", + "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string", + "default": "_all" + }, + "examples": { + "all": { + "summary": "All fields will be returned (default behaviour)", + "value": "_all" + }, + "customSet": { + "summary": "Only fields date and insulin will be returned", + "value": "date,insulin" + } + } + } + ], + "responses": { + "200": { + "description": "Changed documents since specified timestamp", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModifiedMaximum" + }, + "ETag": { + "$ref": "#/components/schemas/headerEtagLastModifiedMaximum" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + } + } + }, + "204": { + "description": "No changes detected" + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "406": { + "description": "The requested content type (in `Accept` header) is not supported." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/{collection}/history/{lastModified}": { + "get": { + "tags": [ + "generic" + ], + "summary": "HISTORY: Retrieves incremental changes since timestamp", + "description": "This HISTORY operation variant is more precise than the previous one with `Last-Modified` request HTTP header), because it does not loose milliseconds precision.\n\nSince this variant queries for changed documents by timestamp precisely and exclusively, the last modified document does not repeat itself in following calls. That is the reason why is this variant more suitable for continuous synchronization with other systems.\n\nThis variant behaves quite the same as the previous one in all other aspects.", + "operationId": "HISTORY2", + "parameters": [ + { + "name": "collection", + "in": "path", + "description": "Collection to which the operation is targeted", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "$ref": "#/components/schemas/paramCollection" + } + }, + { + "name": "lastModified", + "in": "path", + "description": "Starting timestamp (in UNIX epoch format, defined with respect to server's clock) since which the changes in documents are to be listed. Query for modified documents is made using \"greater than\" operator (not including equal timestamps).", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "Maximum number of documents to get in result array", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 1, + "type": "integer", + "example": 100 + } + }, + { + "name": "fields", + "in": "query", + "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string", + "default": "_all" + }, + "examples": { + "all": { + "summary": "All fields will be returned (default behaviour)", + "value": "_all" + }, + "customSet": { + "summary": "Only fields date and insulin will be returned", + "value": "date,insulin" + } + } + } + ], + "responses": { + "200": { + "description": "Changed documents since specified timestamp", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModifiedMaximum" + }, + "ETag": { + "$ref": "#/components/schemas/headerEtagLastModifiedMaximum" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + } + } + }, + "204": { + "description": "No changes detected" + }, + "400": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404": { + "description": "The collection or document specified was not found." + }, + "406": { + "description": "The requested content type (in `Accept` header) is not supported." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/version": { + "get": { + "tags": [ + "other" + ], + "summary": "VERSION: Returns actual version information", + "description": "No authentication is needed for this commnad (it is public)", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Version" + } + } + } + } + } + } + }, + "/status": { + "get": { + "tags": [ + "other" + ], + "summary": "STATUS: Returns actual version information and all permissions granted for API", + "description": "This operation requires authorization in contrast with VERSION operation.", + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Status" + } + } + } + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + }, + "/lastModified": { + "get": { + "tags": [ + "other" + ], + "summary": "LAST MODIFIED: Retrieves timestamp of the last modification of every collection", + "description": "LAST MODIFIED operation inspects collections separately (in parallel) and for each of them it finds the date of any last modification (insertion, update, deletion).\nNot only `srvModified`, but also `date` and `created_at` fields are inspected (as a fallback to previous API).\n\nThis operation requires `read` permission for the API and the collections (e.g. `api:treatments:read`). For each collection the permission is checked separately, you will get timestamps only for those collections that you have access to.", + "operationId": "LAST-MODIFIED", + "parameters": [ + { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Successful operation returning the timestamps", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LastModifiedResult" + } + } + } + }, + "401": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + } + }, + "security": [ + { + "apiKeyAuth": [] + } + ] + } + } + }, + "components": { + "schemas": { + "headerLocation": { + "type": "string", + "description": "Location of document - the relative part of URL. This can be used to parse the identifier of just created document.\nExample=/api/v3/treatments/53409478-105f-11e9-ab14-d663bd873d93" + }, + "headerLastModified": { + "type": "string", + "description": "Timestamp of the last document modification on the server, formatted as\n', :: GMT'.\nThis field is relevant only for documents which were somehow modified by API v3 (inserted, updated or deleted) and it was generated using server's clock.\nExample='Wed, 17 Oct 2018 05:13:00 GMT'" + }, + "headerLastModifiedMaximum": { + "type": "string", + "description": "The latest (maximum) `srvModified` field of all returning documents, formatted as\n', :: GMT'.\nExample='Wed, 17 Oct 2018 05:13:00 GMT'" + }, + "headerEtagLastModifiedMaximum": { + "type": "string", + "description": "The latest (maximum) `srvModified` field of all returning documents. This header does not loose milliseconds from the date (unlike the `Last-Modified` header).\nExample='W/\"1525383610088\"'" + }, + "paramCollection": { + "type": "string", + "example": "treatments", + "enum": [ + "devicestatus", + "entries", + "food", + "profile", + "settings", + "treatments" + ] + }, + "paramIdentifier": { + "type": "string", + "example": "53409478-105f-11e9-ab14-d663bd873d93" + }, + "DocumentBase": { + "required": [ + "app", + "date" + ], + "properties": { + "identifier": { + "type": "string", + "description": "Main addressing, required field that identifies document in the collection.\n\nThe client should not create the identifier, the server automatically assigns it when the document is inserted.\n\nThe server calculates the identifier in such a way that duplicate records are automatically merged (deduplicating is made by `date`, `device` and `eventType` fields).\n\nThe best practise for all applications is not to loose identifiers from received documents, but save them carefully for other consumer applications/systems.\n\nAPI v3 has a fallback mechanism in place, for documents without `identifier` field the `identifier` is set to internal `_id`, when reading or addressing these documents.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "53409478-105f-11e9-ab14-d663bd873d93" + }, + "date": { + "type": "integer", + "description": "Required timestamp when the record or event occured, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always stored in a normalized form - UTC with zero offset. If UTC offset was present, it is going to be set in the `utcOffset` field.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "format": "int64", + "example": 1525383610088 + }, + "utcOffset": { + "type": "integer", + "description": "Local UTC offset (timezone) of the event in minutes. This field can be set either directly by the client (in the incoming document) or it is automatically parsed from the `date` field.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": 120 + }, + "app": { + "type": "string", + "description": "Application or system in which the record was entered by human or device for the first time.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "xdrip" + }, + "device": { + "type": "string", + "description": "The device from which the data originated (including serial number of the device, if it is relevant and safe).\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "dexcom G5" + }, + "_id": { + "type": "string", + "description": "Internally assigned database id. This field is for internal server purposes only, clients communicate with API by using identifier field.", + "example": "58e9dfbc166d88cc18683aac" + }, + "srvCreated": { + "type": "integer", + "description": "The server's timestamp of document insertion into the database (Unix epoch in ms). This field appears only for documents which were inserted by API v3.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "format": "int64", + "example": 1525383610088 + }, + "subject": { + "type": "string", + "description": "Name of the security subject (within Nightscout scope) which has created the document. This field is automatically set by the server from the passed token or JWT.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "uploader" + }, + "srvModified": { + "type": "integer", + "description": "The server's timestamp of the last document modification in the database (Unix epoch in ms). This field appears only for documents which were somehow modified by API v3 (inserted, updated or deleted).\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "format": "int64", + "example": 1525383610088 + }, + "modifiedBy": { + "type": "string", + "description": "Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "admin" + }, + "isValid": { + "type": "boolean", + "description": "A flag set by the server only for deleted documents. This field appears only within history operation and for documents which were deleted by API v3 (and they always have a false value)\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": false + }, + "isReadOnly": { + "type": "boolean", + "description": "A flag set by client that locks the document from any changes. Every document marked with `isReadOnly=true` is forever immutable and cannot even be deleted.\n\nAny attempt to modify the read-only document will end with status 422 UNPROCESSABLE ENTITY.", + "example": true + } + }, + "description": "Shared base for all documents" + }, + "DeviceStatus": { + "description": "State of physical device, which is a technical part of the whole T1D compensation system", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "some_property": { + "type": "string", + "description": "..." + } + } + } + ] + }, + "Entry": { + "description": "Blood glucose measurements and CGM calibrations", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "sgv, mbg, cal, etc" + }, + "sgv": { + "type": "number", + "description": "The glucose reading. (only available for sgv types)" + }, + "direction": { + "type": "string", + "description": "Direction of glucose trend reported by CGM. (only available for sgv types)", + "example": "\"DoubleDown\", \"SingleDown\", \"FortyFiveDown\", \"Flat\", \"FortyFiveUp\", \"SingleUp\", \"DoubleUp\", \"NOT COMPUTABLE\", \"RATE OUT OF RANGE\" for xdrip" + }, + "noise": { + "type": "number", + "description": "Noise level at time of reading. (only available for sgv types)" + }, + "filtered": { + "type": "number", + "description": "The raw filtered value directly from CGM transmitter. (only available for sgv types)" + }, + "unfiltered": { + "type": "number", + "description": "The raw unfiltered value directly from CGM transmitter. (only available for sgv types)" + }, + "rssi": { + "type": "number", + "description": "The signal strength from CGM transmitter. (only available for sgv types)" + }, + "units": { + "type": "string", + "description": "The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.", + "example": "\"mg\", \"mmol\"" + } + } + } + ] + }, + "Food": { + "description": "Nutritional values of food", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "food": { + "type": "string", + "description": "food, quickpick" + }, + "category": { + "type": "string", + "description": "Name for a group of related records" + }, + "subcategory": { + "type": "string", + "description": "Name for a second level of groupping" + }, + "name": { + "type": "string", + "description": "Name of the food described" + }, + "portion": { + "type": "number", + "description": "Number of units (e.g. grams) of the whole portion described" + }, + "unit": { + "type": "string", + "description": "Unit for the portion", + "example": "\"g\", \"ml\", \"oz\"" + }, + "carbs": { + "type": "number", + "description": "Amount of carbs in the portion in grams" + }, + "fat": { + "type": "number", + "description": "Amount of fat in the portion in grams" + }, + "protein": { + "type": "number", + "description": "Amount of proteins in the portion in grams" + }, + "energy": { + "type": "number", + "description": "Amount of energy in the portion in kJ" + }, + "gi": { + "type": "number", + "description": "Glycemic index (1=low, 2=medium, 3=high)" + }, + "hideafteruse": { + "type": "boolean", + "description": "Flag used for quickpick" + }, + "hidden": { + "type": "boolean", + "description": "Flag used for quickpick" + }, + "position": { + "type": "number", + "description": "Ordering field for quickpick" + }, + "portions": { + "type": "number", + "description": "component multiplier if defined inside quickpick compound" + }, + "foods": { + "type": "array", + "description": "Neighbour documents (from food collection) that together make a quickpick compound", + "items": { + "$ref": "#/components/schemas/Food" + } + } + } + } + ] + }, + "Profile": { + "description": "Parameters describing body functioning relative to T1D + compensation parameters", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "some_property": { + "type": "string", + "description": "..." + } + } + } + ] + }, + "Settings": { + "description": "A document representing persisted settings of some application or system (it could by Nightscout itself as well). This pack of options serves as a backup or as a shared centralized storage for multiple client instances. It is a probably good idea to `PATCH` the document instead of `UPDATE` operation, e.g. when changing one settings option in a client application.\n\n`identifier` represents a client application name here, e.g. `xdrip` or `aaps`.\n\n`Settings` collection has a more specific authorization required. For the `SEARCH` operation within this collection, you need an `admin` permission, such as `api:settings:admin`. The goal is to isolate individual client application settings.", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "some_property": { + "type": "string", + "description": "..." + } + } + } + ] + }, + "Treatment": { + "description": "T1D compensation action", + "allOf": [ + { + "$ref": "#/components/schemas/DocumentBase" + }, + { + "type": "object", + "properties": { + "eventType": { + "type": "string", + "description": "The type of treatment event.\n\nNote: this field is immutable by the client (it cannot be updated or patched)", + "example": "\"BG Check\", \"Snack Bolus\", \"Meal Bolus\", \"Correction Bolus\", \"Carb Correction\", \"Combo Bolus\", \"Announcement\", \"Note\", \"Question\", \"Exercise\", \"Site Change\", \"Sensor Start\", \"Sensor Change\", \"Pump Battery Change\", \"Insulin Change\", \"Temp Basal\", \"Profile Switch\", \"D.A.D. Alert\", \"Temporary Target\", \"OpenAPS Offline\", \"Bolus Wizard\"" + }, + "glucose": { + "type": "string", + "description": "Current glucose." + }, + "glucoseType": { + "type": "string", + "description": "Method used to obtain glucose, Finger or Sensor.", + "example": "\"Sensor\", \"Finger\", \"Manual\"" + }, + "units": { + "type": "string", + "description": "The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field when `glucose` is entered.", + "example": "\"mg/dl\", \"mmol/l\"" + }, + "carbs": { + "type": "number", + "description": "Amount of carbs given." + }, + "protein": { + "type": "number", + "description": "Amount of protein given." + }, + "fat": { + "type": "number", + "description": "Amount of fat given." + }, + "insulin": { + "type": "number", + "description": "Amount of insulin, if any." + }, + "duration": { + "type": "number", + "description": "Duration in minutes." + }, + "preBolus": { + "type": "number", + "description": "How many minutes the bolus was given before the meal started." + }, + "splitNow": { + "type": "number", + "description": "Immediate part of combo bolus (in percent)." + }, + "splitExt": { + "type": "number", + "description": "Extended part of combo bolus (in percent)." + }, + "percent": { + "type": "number", + "description": "Eventual basal change in percent." + }, + "absolute": { + "type": "number", + "description": "Eventual basal change in absolute value (insulin units per hour)." + }, + "targetTop": { + "type": "number", + "description": "Top limit of temporary target." + }, + "targetBottom": { + "type": "number", + "description": "Bottom limit of temporary target." + }, + "profile": { + "type": "string", + "description": "Name of the profile to which the pump has been switched." + }, + "reason": { + "type": "string", + "description": "For example the reason why the profile has been switched or why the temporary target has been set." + }, + "notes": { + "type": "string", + "description": "Description/notes of treatment." + }, + "enteredBy": { + "type": "string", + "description": "Who entered the treatment." + } + } + } + ] + }, + "DocumentToPost": { + "type": "object", + "description": "Single document", + "example": { + "identifier": "53409478-105f-11e9-ab14-d663bd873d93", + "date": 1532936118000, + "utcOffset": 120, + "carbs": 10, + "insulin": 1, + "eventType": "Snack Bolus", + "app": "xdrip", + "subject": "uploader" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DeviceStatus" + }, + { + "$ref": "#/components/schemas/Entry" + }, + { + "$ref": "#/components/schemas/Food" + }, + { + "$ref": "#/components/schemas/Profile" + }, + { + "$ref": "#/components/schemas/Settings" + }, + { + "$ref": "#/components/schemas/Treatment" + } + ] + }, + "Document": { + "type": "object", + "description": "Single document", + "example": { + "identifier": "53409478-105f-11e9-ab14-d663bd873d93", + "date": 1532936118000, + "utcOffset": 120, + "carbs": 10, + "insulin": 1, + "eventType": "Snack Bolus", + "srvCreated": 1532936218000, + "srvModified": 1532936218000, + "app": "xdrip", + "subject": "uploader", + "modifiedBy": "admin" + }, + "xml": { + "name": "item" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DeviceStatus" + }, + { + "$ref": "#/components/schemas/Entry" + }, + { + "$ref": "#/components/schemas/Food" + }, + { + "$ref": "#/components/schemas/Profile" + }, + { + "$ref": "#/components/schemas/Settings" + }, + { + "$ref": "#/components/schemas/Treatment" + } + ] + }, + "DeviceStatusArray": { + "type": "array", + "description": "Array of documents", + "items": { + "$ref": "#/components/schemas/DeviceStatus" + } + }, + "EntryArray": { + "type": "array", + "description": "Array of documents", + "items": { + "$ref": "#/components/schemas/Entry" + } + }, + "FoodArray": { + "type": "array", + "description": "Array of documents", + "items": { + "$ref": "#/components/schemas/Food" + } + }, + "ProfileArray": { + "type": "array", + "description": "Array of documents", + "items": { + "$ref": "#/components/schemas/Profile" + } + }, + "SettingsArray": { + "type": "array", + "description": "Array of settings", + "items": { + "$ref": "#/components/schemas/Settings" + } + }, + "TreatmentArray": { + "type": "array", + "description": "Array of documents", + "items": { + "$ref": "#/components/schemas/Treatment" + } + }, + "DocumentArray": { + "type": "object", + "xml": { + "name": "items" + }, + "oneOf": [ + { + "$ref": "#/components/schemas/DeviceStatusArray" + }, + { + "$ref": "#/components/schemas/EntryArray" + }, + { + "$ref": "#/components/schemas/FoodArray" + }, + { + "$ref": "#/components/schemas/ProfileArray" + }, + { + "$ref": "#/components/schemas/SettingsArray" + }, + { + "$ref": "#/components/schemas/TreatmentArray" + } + ] + }, + "Version": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "The whole Nightscout instance version", + "example": "0.10.2-release-20171201" + }, + "apiVersion": { + "type": "string", + "description": "API v3 subsystem version", + "example": "3.0.0" + }, + "srvDate": { + "type": "number", + "description": "Actual server date and time in UNIX epoch format", + "example": 1532936118000 + }, + "storage": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Type of storage engine used", + "example": "mongodb" + }, + "version": { + "type": "string", + "description": "Version of the storage engine", + "example": "4.0.6" + } + } + } + }, + "description": "Information about versions" + }, + "Status": { + "description": "Information about versions and API permissions", + "allOf": [ + { + "$ref": "#/components/schemas/Version" + }, + { + "type": "object", + "properties": { + "apiPermissions": { + "type": "object", + "properties": { + "devicestatus": { + "type": "string", + "example": "crud" + }, + "entries": { + "type": "string", + "example": "r" + }, + "food": { + "type": "string", + "example": "crud" + }, + "profile": { + "type": "string", + "example": "r" + }, + "treatments": { + "type": "string", + "example": "crud" + } + } + } + } + } + ] + }, + "LastModifiedResult": { + "properties": { + "srvDate": { + "type": "integer", + "description": "Actual storage server date (Unix epoch in ms).", + "format": "int64", + "example": 1556260878776 + }, + "collections": { + "type": "object", + "properties": { + "devicestatus": { + "type": "integer", + "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "format": "int64", + "example": 1556260760974 + }, + "treatments": { + "type": "integer", + "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "format": "int64", + "example": 1553374184169 + }, + "entries": { + "type": "integer", + "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "format": "int64", + "example": 1556260758768 + }, + "profile": { + "type": "integer", + "description": "Timestamp of the last modification (Unix epoch in ms), `null` when there is no timestamp found.", + "format": "int64", + "example": 1548524042744 + } + }, + "description": "Collections which the user have read access to." + } + }, + "description": "Result of LAST MODIFIED operation" + } + }, + "responses": { + "201Created": { + "description": "Successfully created a new document in collection", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + } + }, + "201CreatedLocation": { + "description": "Successfully created a new document in collection", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "204NoContent": { + "description": "Successfully finished operation", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + } + }, + "204NoContentLocation": { + "description": "Successfully finished operation", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + }, + "Location": { + "$ref": "#/components/schemas/headerLocation" + } + } + }, + "304NotModified": { + "description": "The document has not been modified on the server since timestamp specified in If-Modified-Since header", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + } + }, + "400BadRequest": { + "description": "The request is malformed. There may be some required parameters missing or there are unrecognized parameters present." + }, + "401Unauthorized": { + "description": "The request was not successfully authenticated using access token or JWT, or the request has missing `Date` header or it contains an expired timestamp, so that the request cannot continue due to the security policy." + }, + "403Forbidden": { + "description": "Insecure HTTP scheme used or the request has been successfully authenticated, but the security subject is not authorized for the operation." + }, + "404NotFound": { + "description": "The collection or document specified was not found." + }, + "406NotAcceptable": { + "description": "The requested content type (in `Accept` header) is not supported." + }, + "412PreconditionFailed": { + "description": "The document has already been modified on the server since specified timestamp (in If-Unmodified-Since header)." + }, + "410Gone": { + "description": "The requested document has already been deleted." + }, + "422UnprocessableEntity": { + "description": "The client request is well formed but a server validation error occured. Eg. when trying to modify or delete a read-only document (having `isReadOnly=true`)." + }, + "search200": { + "description": "Successful operation returning array of documents matching the filtering criteria", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + } + } + }, + "search204": { + "description": "Successful operation - no documents matching the filtering criteria" + }, + "read200": { + "description": "The document has been succesfully found and its JSON form returned in the response content.", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModified" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Document" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/Document" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/Document" + } + } + } + }, + "history200": { + "description": "Changed documents since specified timestamp", + "headers": { + "Last-Modified": { + "$ref": "#/components/schemas/headerLastModifiedMaximum" + }, + "ETag": { + "$ref": "#/components/schemas/headerEtagLastModifiedMaximum" + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "text/csv": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + }, + "application/xml": { + "schema": { + "$ref": "#/components/schemas/DocumentArray" + } + } + } + }, + "history204": { + "description": "No changes detected" + }, + "lastModified200": { + "description": "Successful operation returning the timestamps", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LastModifiedResult" + } + } + } + } + }, + "parameters": { + "dateHeader": { + "name": "Date", + "in": "header", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory header serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `now` query parameter.\nExample:\n\n
Date: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + "nowParam": { + "name": "now", + "in": "query", + "description": "Timestamp (defined by client's clock) when the HTTP request was constructed on client. This mandatory parameter serves as an anti-replay precaution. After a period of time (specified by `API3_TIME_SKEW_TOLERANCE`) the message won't be valid any more and it will be denied with HTTP 401 Unauthorized code. This can be set alternatively in `Date` header.\n\nExample:\n\n
now=1525383610088
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "integer", + "format": "int64" + } + }, + "tokenParam": { + "name": "token", + "in": "query", + "description": "An alternative way of authorization - passing accessToken in a query parameter.\n\nExample:\n\n
token=testadmin-bf2591231bd2c042
", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + "limitParam": { + "name": "limit", + "in": "query", + "description": "Maximum number of documents to get in result array", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 1, + "type": "integer", + "example": 100 + } + }, + "skipParam": { + "name": "skip", + "in": "query", + "description": "Number of documents to skip from collection query before loading them into result array (used for pagination)", + "required": false, + "style": "form", + "explode": true, + "schema": { + "minimum": 0, + "type": "integer", + "example": 0, + "default": 0 + } + }, + "sortParam": { + "name": "sort", + "in": "query", + "description": "Field name by which the sorting of documents is performed. This parameter cannot be combined with `sort$desc` parameter.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + "sortDescParam": { + "name": "sort$desc", + "in": "query", + "description": "Field name by which the descending (reverse) sorting of documents is performed. This parameter cannot be combined with `sort` parameter.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + "permanentParam": { + "name": "permanent", + "in": "query", + "description": "If true, the deletion will be irreversible and it will not appear in `HISTORY` operation. Normally there is no reason for setting this flag.", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "boolean" + } + }, + "fieldsParam": { + "name": "fields", + "in": "query", + "description": "A chosen set of fields to return in response. Either you can enumerate specific fields of interest or use the predefined set. Sample parameter values:\n\n_all: All fields will be returned (default value)\n\ndate,insulin: Only fields `date` and `insulin` will be returned", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string", + "default": "_all" + }, + "examples": { + "all": { + "summary": "All fields will be returned (default behaviour)", + "value": "_all" + }, + "customSet": { + "summary": "Only fields date and insulin will be returned", + "value": "date,insulin" + } + } + }, + "filterParams": { + "name": "filter_parameters", + "in": "query", + "description": "Any number of filtering operators.\n\nEach filtering operator has name like `$`, e.g. `carbs$gt=2` which represents filtering rule \"The field carbs must be present and greater than 2\".\n\nYou can choose from operators:\n\n`eq`=equals, `insulin$eq=1.5`\n\n`ne`=not equals, `insulin$ne=1.5`\n\n`gt`=greater than, `carbs$gt=30`\n\n`gte`=greater than or equal, `carbs$gte=30`\n\n`lt`=less than, `carbs$lt=30`\n\n`lte`=less than or equal, `carbs$lte=30`\n\n`in`=in specified set, `type$in=sgv|mbg|cal`\n\n`nin`=not in specified set, `eventType$nin=Temp%20Basal|Temporary%20Target`\n\n`re`=regex pattern, `eventType$re=Temp.%2A`\n\nWhen filtering by field `date`, `created_at`, `srvModified` or `srvCreated`, you can choose from three input formats\n- Unix epoch in milliseconds (1525383610088)\n- Unix epoch in seconds (1525383610)\n- ISO 8601 with optional timezone ('2018-05-03T21:40:10.088Z' or '2018-05-03T23:40:10.088+02:00')\n\nThe date is always queried in a normalized form - UTC with zero offset and with the correct format (1525383610088 for `date`, '2018-05-03T21:40:10.088Z' for `created_at`).", + "required": false, + "style": "form", + "explode": true, + "schema": { + "type": "string" + } + }, + "lastModifiedRequiredHeader": { + "name": "Last-Modified", + "in": "header", + "description": "Starting timestamp (defined with respect to server's clock) since which the changes in documents are to be listed, formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nExample:\n\n
Last-Modified: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": true, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + "ifModifiedSinceHeader": { + "name": "If-Modified-Since", + "in": "header", + "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Modified-Since: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + }, + "ifUnmodifiedSinceHeader": { + "name": "If-Unmodified-Since", + "in": "header", + "description": "Timestamp (defined with respect to server's clock) of the last document modification formatted as:\n\n<day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT\n\nIf this header is present, the operation will compare its value with the srvModified timestamp of the document at first and the operation result then may differ. The srvModified timestamp was defined by server's clock.\n\nExample:\n\n
If-Unmodified-Since: Wed, 17 Oct 2018 05:13:00 GMT
", + "required": false, + "style": "simple", + "explode": false, + "schema": { + "type": "string" + } + } + }, + "securitySchemes": { + "accessToken": { + "type": "apiKey", + "description": "Add token as query item in the URL or as HTTP header. You can manage access token in `/admin`.\nEach operation requires a specific permission that has to be granted (via security role) to the security subject, which was authenticated by `token` parameter/header or `JWT`. E.g. for creating new `devicestatus` document via API you need `api:devicestatus:create` permission.", + "name": "token", + "in": "query" + }, + "jwtoken": { + "type": "http", + "description": "Use this if you know the temporary json webtoken.", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } +} diff --git a/lib/authorization/storage.js b/lib/authorization/storage.js index c032018d170..d602470add6 100644 --- a/lib/authorization/storage.js +++ b/lib/authorization/storage.js @@ -210,16 +210,28 @@ function init (env, ctx) { if (!accessToken) return null; - var split_token = accessToken.split('-'); - var prefix = split_token ? _.last(split_token) : ''; - if (prefix.length < 16) { - return null; - } + function checkToken(accessToken) { + var split_token = accessToken.split('-'); + var prefix = split_token ? _.last(split_token) : ''; - return _.find(storage.subjects, function matches (subject) { - return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0; - }); + if (prefix.length < 16) { + return null; + } + + return _.find(storage.subjects, function matches (subject) { + return subject.accessTokenDigest.indexOf(accessToken) === 0 || subject.digest.indexOf(prefix) === 0; + }); + } + + if (!Array.isArray(accessToken)) accessToken = [accessToken]; + + for (let i=0; i < accessToken.length; i++) { + const subject = checkToken(accessToken[i]); + if (subject) return subject; + } + + return null; }; storage.doesAccessTokenExist = function doesAccessTokenExist(accessToken) { diff --git a/lib/client/clock-client.js b/lib/client/clock-client.js index 891f10d57d5..73ac9c3baca 100644 --- a/lib/client/clock-client.js +++ b/lib/client/clock-client.js @@ -1,53 +1,55 @@ 'use strict'; -const browserSettings = require('./browser-settings'); - +var browserSettings = require('./browser-settings'); var client = {}; +var latestProperties = {}; client.settings = browserSettings(client, window.serverSettings, $); -//console.log('settings', client.settings); -// client.settings now contains all settings - client.query = function query () { - console.log('query'); var parts = (location.search || '?').substring(1).split('&'); var token = ''; - parts.forEach(function (val) { + parts.forEach(function(val) { if (val.startsWith('token=')) { token = val.substring('token='.length); } }); var secret = localStorage.getItem('apisecrethash'); - var src = '/api/v1/entries.json?find[type]=sgv&count=3&t=' + new Date().getTime(); + var src = '/api/v2/properties'; // Use precalculated data from the backend if (secret) { - src += '&secret=' + secret; + var s = '?secret=' + secret; + src += s; } else if (token) { - src += '&token=' + token; + var s2 = '?token=' + token; + src += s2; } $.ajax(src, { - success: client.render + error: function gotError (err) { + console.error(err); + } + , success: function gotData (data) { + latestProperties = data; + client.render(); + } }); }; -client.render = function render (xhr) { - console.log('got data', xhr); +client.render = function render () { - let rec; - let delta; + if (!latestProperties.bgnow && !latestProperties.bgnow.sgvs) { + console.error('BG data not available'); + return; + } - // Get SGV, calculate DELTA - xhr.forEach(element => { - if (element.sgv && !rec) { - rec = element; - } - else if (element.sgv && rec && delta==null) { - delta = (rec.sgv - element.sgv)/((rec.date - element.date)/(5*60*1000)); - } - }); + let rec = latestProperties.bgnow.sgvs[0]; + let deltaDisplayValue; + + if (latestProperties.delta) { + deltaDisplayValue = latestProperties.delta.display; + } let $errorMessage = $('#errorMessage'); let $inner = $('#inner'); @@ -71,15 +73,12 @@ client.render = function render (xhr) { // Backward compatible if (face === 'clock-color') { - face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg40-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar30-nl-ag6'; - } - else if (face === 'clock') { + face = 'c' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6'; + } else if (face === 'clock') { face = 'bn0-sg40'; - } - else if (face === 'bgclock') { - face = 'bn0-sg30-ar18-nl-nl-tm26'; - } - else if (face === 'config') { + } else if (face === 'bgclock') { + face = 'b' + (window.serverSettings.settings.showClockLastTime ? 'y' : 'n') + '13-sg35-' + (window.serverSettings.settings.showClockDelta ? 'dt14-' : '') + 'nl-ar25-nl-ag6'; + } else if (face === 'config') { face = $inner.attr('data-face-config'); $inner.empty(); } @@ -95,46 +94,19 @@ client.render = function render (xhr) { if (param === '0') { bgColor = (faceParams[param].substr(0, 1) === 'c'); // do we want colorful background? alwaysShowTime = (faceParams[param].substr(1, 1) === 'y'); // always show "stale time" text? - staleMinutes = (faceParams[param].substr(2,2) - 0 >= 0) ? faceParams[param].substr(2,2) : 13; // threshold value (0=never) - } else if (!clockCreated){ - let div = '
0) ? ' style="' + ((faceParams[param].substr(0,2) === 'ar') ? 'height' : 'font-size') + ':' + faceParams[param].substr(2,2) + 'vmin"' : '') + '>
'; + staleMinutes = (faceParams[param].substr(2, 2) - 0 >= 0) ? faceParams[param].substr(2, 2) : 13; // threshold value (0=never) + } else if (!clockCreated) { + let div = '
0) ? ' style="' + ((faceParams[param].substr(0, 2) === 'ar') ? 'height' : 'font-size') + ':' + faceParams[param].substr(2, 2) + 'vmin"' : '') + '>
'; $inner.append(div); } } // Convert BG to mmol/L if necessary. - let displayValue; - let deltaDisplayValue; - - if (window.serverSettings.settings.units === 'mmol') { - displayValue = window.Nightscout.units.mgdlToMMOL(rec.sgv); - deltaDisplayValue = window.Nightscout.units.mgdlToMMOL(delta); - } else { - displayValue = rec.sgv; - deltaDisplayValue = Math.round(delta); - } - - if (deltaDisplayValue > 0) { - deltaDisplayValue = '+' + deltaDisplayValue; - } + let displayValue = rec.scaled; // Insert the delta value text. $('.dt').html(deltaDisplayValue); - // Generate and insert the clock. - let timeDivisor = parseInt(client.settings.timeFormat ? client.settings.timeFormat : 12, 10); - let today = new Date() - , h = today.getHours() % timeDivisor; - if (timeDivisor === 12) { - h = (h === 0) ? 12 : h; // In the case of 00:xx, change to 12:xx for 12h time - } - if (timeDivisor === 24) { - h = (h < 10) ? ("0" + h) : h; // Pad the hours with a 0 in 24h time - } - let m = today.getMinutes(); - if (m < 10) m = "0" + m; - $('.tm').html(h + ":" + m); - // Color background if (bgColor) { @@ -150,7 +122,7 @@ client.render = function render (xhr) { let bgTargetBottom = client.settings.thresholds.bgTargetBottom; let bgTargetTop = client.settings.thresholds.bgTargetTop; - let bgNum = parseFloat(rec.sgv); + let bgNum = parseFloat(rec.mgdl); // Threshold background coloring. if (bgNum < bgLow) { @@ -169,20 +141,16 @@ client.render = function render (xhr) { $('body').css('background-color', red); } - } - else { + } else { $('body').css('background-color', 'black'); } // Time before data considered stale. let threshold = 1000 * 60 * staleMinutes; - let last = new Date(rec.date); - let now = new Date(); - - let elapsedMins = Math.round(((now - last) / 1000) / 60); - - let thresholdReached = (now - last > threshold) && threshold > 0; + var elapsedms = Date.now() - rec.mills; + let elapsedMins = Math.floor((elapsedms / 1000) / 60); + let thresholdReached = (elapsedms > threshold) && threshold > 0; // Insert the BG value text, toggle stale if necessary. $('.sg').toggleClass('stale', thresholdReached).html(displayValue); @@ -191,17 +159,14 @@ client.render = function render (xhr) { let staleTimeText; if (elapsedMins === 0) { staleTimeText = 'Just now'; - } - else if (elapsedMins === 1) { + } else if (elapsedMins === 1) { staleTimeText = '1 minute ago'; - } - else { + } else { staleTimeText = elapsedMins + ' minutes ago'; } $('.ag').html(staleTimeText); - } - else { + } else { $('.ag').html(''); } @@ -216,12 +181,33 @@ client.render = function render (xhr) { $('body').css('color', bgColor ? 'white' : 'grey'); $('.ar').css('filter', bgColor ? 'brightness(100%)' : 'brightness(50%)').html(arrow); } + + updateClock(); + }; +function updateClock () { + let timeDivisor = parseInt(client.settings.timeFormat ? client.settings.timeFormat : 12, 10); + let today = new Date() + , h = today.getHours() % timeDivisor; + if (timeDivisor === 12) { + h = (h === 0) ? 12 : h; // In the case of 00:xx, change to 12:xx for 12h time + } + if (timeDivisor === 24) { + h = (h < 10) ? ("0" + h) : h; // Pad the hours with a 0 in 24h time + } + let m = today.getMinutes(); + if (m < 10) m = "0" + m; + $('.tm').html(h + ":" + m); +} + client.init = function init () { - console.log('init'); + console.log('Initializing clock'); client.query(); - setInterval(client.query, 1 * 60 * 1000); + setInterval(client.query, 20 * 1000); // update every 20 seconds + + // time update + setInterval(updateClock, 1000); }; module.exports = client; diff --git a/lib/client/index.js b/lib/client/index.js index c329c5cec0b..53515e3b943 100644 --- a/lib/client/index.js +++ b/lib/client/index.js @@ -62,6 +62,12 @@ client.init = function init (callback) { , url: src , headers: client.headers() }).done(function success (serverSettings) { + if (serverSettings.runtimeState !== 'loaded') { + console.log('Server is still loading data'); + $('#loadingMessageText').html('Server is starting and still loading data, retrying load in 5 seconds'); + window.setTimeout(window.Nightscout.client.init(), 5000); + return; + } client.settingsFailed = false; console.log('Application appears to be online'); $('#centerMessagePanel').hide(); @@ -71,8 +77,8 @@ client.init = function init (callback) { // check if we couldn't reach the server at all, show offline message if (!jqXHR.readyState) { console.log('Application appears to be OFFLINE'); - $('#loadingMessageText').html('Connecting to Nightscout server failed, retrying every 2 seconds'); - window.setTimeout(window.Nightscout.client.init(), 2000); + $('#loadingMessageText').html('Connecting to Nightscout server failed, retrying every 5 seconds'); + window.setTimeout(window.Nightscout.client.init(), 5000); return; } diff --git a/lib/data/dataloader.js b/lib/data/dataloader.js index 7074b18e1fb..985ea259de5 100644 --- a/lib/data/dataloader.js +++ b/lib/data/dataloader.js @@ -392,7 +392,7 @@ function loadSensorAndInsulinTreatments(ddata, ctx, callback) { function loadLatestSingle(ddata, ctx, dataType, callback) { var dateRange = { - $gte: new Date(ddata.lastUpdated - (constants.ONE_DAY * 32)).toISOString() + $gte: new Date(ddata.lastUpdated - (constants.ONE_DAY * 62)).toISOString() }; if (ddata.page && ddata.page.frame) { diff --git a/lib/language.js b/lib/language.js index ac9b0a02218..5246208ff1c 100644 --- a/lib/language.js +++ b/lib/language.js @@ -23,6 +23,7 @@ function init() { , { code: 'fr', language: 'Français', speechCode: 'fr-FR' } , { code: 'he', language: 'עברית', speechCode: 'he-IL' } , { code: 'hr', language: 'Hrvatski', speechCode: 'hr-HR' } + , { code: 'hu', language: 'Magyar', speechCode: 'hu-HU' } , { code: 'it', language: 'Italiano', speechCode: 'it-IT' } , { code: 'ja', language: '日本語', speechCode: 'ja-JP' } , { code: 'ko', language: '한국어', speechCode: 'ko-KR' } @@ -65,6 +66,7 @@ function init() { ,ko: '포트에서 수신' ,tr: 'Port dinleniyor' ,zh_cn: '正在监听端口' + ,hu: 'Port figyelése' } // Client ,'Mo' : { @@ -91,6 +93,7 @@ function init() { ,ko: '월' ,tr: 'Pzt' ,zh_cn: '一' + ,hu: 'Hé' } ,'Tu' : { cs: 'Út' @@ -116,6 +119,7 @@ function init() { ,ko: '화' ,tr: 'Sal' ,zh_cn: '二' + ,hu: 'Ke' } ,'We' : { cs: 'St' @@ -141,6 +145,7 @@ function init() { ,ko: '수' ,tr: 'Çar' ,zh_cn: '三' + ,hu: 'Sze' } ,'Th' : { cs: 'Čt' @@ -166,6 +171,7 @@ function init() { ,ko: '목' ,tr: 'Per' ,zh_cn: '四' + ,hu: 'Csü' } ,'Fr' : { cs: 'Pá' @@ -191,6 +197,7 @@ function init() { ,ko: '금' ,tr: 'Cum' ,zh_cn: '五' + ,hu: 'Pé' } ,'Sa' : { cs: 'So' @@ -216,6 +223,7 @@ function init() { ,ko: '토' ,tr: 'Cmt' ,zh_cn: '六' + ,hu: 'Szo' } ,'Su' : { cs: 'Ne' @@ -241,6 +249,7 @@ function init() { ,ko: '일' ,tr: 'Paz' ,zh_cn: '日' + ,hu: 'Vas' } ,'Monday' : { cs: 'Pondělí' @@ -266,6 +275,7 @@ function init() { ,ko: '월요일' ,tr: 'Pazartesi' ,zh_cn: '星期一' + ,hu: 'Hétfő' } ,'Tuesday' : { cs: 'Úterý' @@ -291,6 +301,7 @@ function init() { ,ko: '화요일' ,tr: 'Salı' ,zh_cn: '星期二' + ,hu: 'Kedd' } ,'Wednesday' : { cs: 'Středa' @@ -316,6 +327,7 @@ function init() { ,ko: '수요일' ,tr: 'Çarşamba' ,zh_cn: '星期三' + ,hu: 'Szerda' } ,'Thursday' : { cs: 'Čtvrtek' @@ -341,6 +353,7 @@ function init() { ,ko: '목요일' ,tr: 'Perşembe' ,zh_cn: '星期四' + ,hu: 'Csütörtök' } ,'Friday' : { cs: 'Pátek' @@ -366,6 +379,7 @@ function init() { ,ko: '금요일' ,tr: 'Cuma' ,zh_cn: '星期五' + ,hu: 'Péntek' } ,'Saturday' : { cs: 'Sobota' @@ -391,6 +405,7 @@ function init() { ,ko: '토요일' ,tr: 'Cumartesi' ,zh_cn: '星期六' + ,hu: 'Szombat' } ,'Sunday' : { cs: 'Neděle' @@ -416,6 +431,7 @@ function init() { ,ko: '일요일' ,tr: 'Pazar' ,zh_cn: '星期日' + ,hu: 'Vasárnap' } ,'Category' : { cs: 'Kategorie' @@ -441,6 +457,7 @@ function init() { ,ko: '분류' ,tr: 'Kategori' ,zh_cn: '类别' + ,hu: 'Kategória' } ,'Subcategory' : { cs: 'Podkategorie' @@ -466,6 +483,7 @@ function init() { ,ko: '세부 분류' ,tr: 'Altkategori' ,zh_cn: '子类别' + ,hu: 'Alkategória' } ,'Name' : { cs: 'Jméno' @@ -491,6 +509,7 @@ function init() { ,ko: '프로파일 명' ,tr: 'İsim' ,zh_cn: '名称' + ,hu: 'Név' } ,'Today' : { cs: 'Dnes' @@ -516,6 +535,7 @@ function init() { ,ko: '오늘' ,tr: 'Bugün' ,zh_cn: '今天' + ,hu: 'Ma' } ,'Last 2 days' : { cs: 'Poslední 2 dny' @@ -541,6 +561,7 @@ function init() { ,ko: '지난 2일' ,tr: 'Son 2 gün' ,zh_cn: '过去2天' + ,hu: 'Utolsó 2 nap' } ,'Last 3 days' : { cs: 'Poslední 3 dny' @@ -566,6 +587,7 @@ function init() { ,ko: '지난 3일' ,tr: 'Son 3 gün' ,zh_cn: '过去3天' + ,hu: 'Utolsó 3 nap' } ,'Last week' : { cs: 'Poslední týden' @@ -591,6 +613,7 @@ function init() { ,ko: '지난주' ,tr: 'Geçen Hafta' ,zh_cn: '上周' + ,hu: 'Előző hét' } ,'Last 2 weeks' : { cs: 'Poslední 2 týdny' @@ -616,6 +639,7 @@ function init() { ,ko: '지난 2주' ,tr: 'Son 2 hafta' ,zh_cn: '过去2周' + ,hu: 'Előző 2 hét' } ,'Last month' : { cs: 'Poslední měsíc' @@ -641,6 +665,7 @@ function init() { ,ko: '지난달' ,tr: 'Geçen Ay' ,zh_cn: '上个月' + ,hu: 'Előző hónap' } ,'Last 3 months' : { cs: 'Poslední 3 měsíce' @@ -666,6 +691,7 @@ function init() { ,ko: '지난 3달' ,tr: 'Son 3 ay' ,zh_cn: '过去3个月' + ,hu: 'Előző 3 hónap' } , 'between': { cs: 'between' @@ -691,6 +717,7 @@ function init() { ,ko: 'between' ,tr: 'between' ,zh_cn: 'between' + ,hu: 'között' } , 'around': { cs: 'around' @@ -716,6 +743,7 @@ function init() { ,ko: 'around' ,tr: 'around' ,zh_cn: 'around' + ,hu: 'körülbelül' } , 'and': { cs: 'and' @@ -741,6 +769,7 @@ function init() { ,ko: 'and' ,tr: 'and' ,zh_cn: 'and' + ,hu: 'és' } ,'From' : { cs: 'Od' @@ -766,6 +795,7 @@ function init() { ,ko: '시작일' ,tr: 'Başlangıç' ,zh_cn: '从' + ,hu: 'Tól' } ,'To' : { cs: 'Do' @@ -791,6 +821,7 @@ function init() { ,ko: '종료일' ,tr: 'Bitiş' ,zh_cn: '到' + ,hu: 'Ig' } ,'Notes' : { cs: 'Poznámky' @@ -816,6 +847,7 @@ function init() { ,ko: '메모' ,tr: 'Not' ,zh_cn: '记录' + ,hu: 'Jegyzetek' } ,'Food' : { cs: 'Jídlo' @@ -841,6 +873,7 @@ function init() { ,ko: '음식' ,tr: 'Gıda' ,zh_cn: '食物' + ,hu: 'Étel' } ,'Insulin' : { cs: 'Inzulín' @@ -866,6 +899,7 @@ function init() { ,ko: '인슐린' ,tr: 'İnsülin' ,zh_cn: '胰岛素' + ,hu: 'Inzulin' } ,'Carbs' : { cs: 'Sacharidy' @@ -891,6 +925,7 @@ function init() { ,ko: '탄수화물' ,tr: 'Karbonhidrat' ,zh_cn: '碳水化合物' + ,hu: 'Szénhidrát' } ,'Notes contain' : { cs: 'Poznámky obsahují' @@ -916,8 +951,9 @@ function init() { ,ko: '메모 포함' ,tr: 'Notlar içerir' ,zh_cn: '记录包括' + ,hu: 'Jegyzet tartalmazza' } - ,'Target bg range bottom' : { + ,'Target BG range bottom' : { cs: 'Cílová glykémie spodní' ,de: 'Vorgabe unteres BG-Ziel' ,es: 'Objetivo inferior de glucemia' @@ -941,6 +977,7 @@ function init() { ,ko: '최저 목표 혈당 범위' ,tr: 'Hedef KŞ aralığı düşük' ,zh_cn: '目标血糖范围 下限' + ,hu: 'Alsó cukorszint határ' } ,'top' : { cs: 'horní' @@ -966,6 +1003,7 @@ function init() { ,ko: '최고치' ,tr: 'Üstü' ,zh_cn: '上限' + ,hu: 'Felső' } ,'Show' : { cs: 'Zobraz' @@ -991,6 +1029,7 @@ function init() { ,ko: '확인' ,tr: 'Göster' ,zh_cn: '生成' + ,hu: 'Mutasd' } ,'Display' : { cs: 'Zobraz' @@ -1016,6 +1055,7 @@ function init() { ,ko: '출력' ,tr: 'Görüntüle' ,zh_cn: '显示' + ,hu: 'Ábrázol' } ,'Loading' : { cs: 'Nahrávám' @@ -1041,6 +1081,7 @@ function init() { ,ko: '로딩' ,tr: 'Yükleniyor' ,zh_cn: '载入中' + ,hu: 'Betöltés' } ,'Loading profile' : { cs: 'Nahrávám profil' @@ -1066,6 +1107,7 @@ function init() { ,ko: '프로파일 로딩' ,tr: 'Profil yükleniyor' ,zh_cn: '载入配置文件' + ,hu: 'Profil betöltése' } ,'Loading status' : { cs: 'Nahrávám status' @@ -1091,6 +1133,7 @@ function init() { ,ko: '상태 로딩' ,tr: 'Durum Yükleniyor' ,zh_cn: '载入状态' + ,hu: 'Állapot betöltése' } ,'Loading food database' : { cs: 'Nahrávám databázi jídel' @@ -1116,6 +1159,7 @@ function init() { ,ko: '음식 데이터 베이스 로딩' ,tr: 'Gıda veritabanı yükleniyor' ,zh_cn: '载入食物数据库' + ,hu: 'Étel adatbázis betöltése' } ,'not displayed' : { cs: 'není zobrazeno' @@ -1141,6 +1185,7 @@ function init() { ,ko: '출력되지 않음' ,tr: 'görüntülenmedi' ,zh_cn: '未显示' + ,hu: 'nincs megjelenítve' } ,'Loading CGM data of' : { cs: 'Nahrávám CGM data' @@ -1166,6 +1211,7 @@ function init() { ,ko: 'CGM 데이터 로딩' ,tr: 'den CGM veriler yükleniyor' ,zh_cn: '载入CGM(连续血糖监测)数据从' + ,hu: 'CGM adatok betöltése' } ,'Loading treatments data of' : { cs: 'Nahrávám data ošetření' @@ -1191,6 +1237,7 @@ function init() { ,ko: '처리 데이터 로딩' ,tr: 'dan Tedavi verilerini yükle' ,zh_cn: '载入操作数据从' + ,hu: 'Kezelés adatainak betöltése' } ,'Processing data of' : { cs: 'Zpracovávám data' @@ -1216,6 +1263,7 @@ function init() { ,ko: '데이터 처리 중' ,tr: 'dan Veri işleme' ,zh_cn: '处理数据从' + ,hu: 'Adatok feldolgozása' } ,'Portion' : { cs: 'Porce' @@ -1241,6 +1289,7 @@ function init() { ,ko: '부분' ,tr: 'Porsiyon' ,zh_cn: '部分' + ,hu: 'Porció' } ,'Size' : { cs: 'Rozměr' @@ -1266,6 +1315,7 @@ function init() { ,ko: '크기' ,tr: 'Boyut' ,zh_cn: '大小' + ,hu: 'Méret' } ,'(none)' : { cs: '(Žádný)' @@ -1292,6 +1342,7 @@ function init() { ,tr: '(hiç)' ,zh_cn: '(无)' ,zh_tw: '(無)' + ,hu: '(semmilyen)' } ,'None' : { cs: 'Žádný' @@ -1318,6 +1369,7 @@ function init() { ,tr: 'Hiç' ,zh_cn: '无' ,zh_tw: '無' + ,hu: 'Semmilyen' } ,'' : { cs: '<Žádný>' @@ -1343,6 +1395,7 @@ function init() { ,ko: '<없음>' ,tr: '' ,zh_cn: '<无>' + ,hu: '' } ,'Result is empty' : { cs: 'Prázdný výsledek' @@ -1368,6 +1421,7 @@ function init() { ,ko: '결과 없음' ,tr: 'Sonuç boş' ,zh_cn: '结果为空' + ,hu: 'Az eredmény üres' } ,'Day to day' : { cs: 'Den po dni' @@ -1393,6 +1447,7 @@ function init() { ,ko: '일별 그래프' ,tr: 'Günden Güne' ,zh_cn: '日到日' + ,hu: 'Napi' } ,'Week to week' : { cs: 'Week to week' @@ -1416,6 +1471,7 @@ function init() { ,nl: 'Week to week' ,ko: '주별 그래프' ,zh_cn: 'Week to week' + ,hu: 'Heti' } ,'Daily Stats' : { cs: 'Denní statistiky' @@ -1441,6 +1497,7 @@ function init() { ,ko: '일간 통계' ,tr: 'Günlük İstatistikler' ,zh_cn: '每日状态' + ,hu: 'Napi statisztika' } ,'Percentile Chart' : { cs: 'Percentil' @@ -1466,6 +1523,7 @@ function init() { ,ko: '백분위 그래프' ,tr: 'Yüzdelik Grafiği' ,zh_cn: '百分位图形' + ,hu: 'Százalékos' } ,'Distribution' : { cs: 'Rozložení' @@ -1491,6 +1549,7 @@ function init() { ,ko: '분포' ,tr: 'Dağılım' ,zh_cn: '分布' + ,hu: 'Szétosztás' } ,'Hourly stats' : { cs: 'Statistika po hodinách' @@ -1516,6 +1575,7 @@ function init() { ,ko: '시간대별 통계' ,tr: 'Saatlik istatistikler' ,zh_cn: '每小时状态' + ,hu: 'Óránkra való szétosztás' } ,'netIOB stats': { // hourlystats.js nl: 'netIOB stats' @@ -1529,6 +1589,7 @@ function init() { , pl: 'Statystyki netIOP' ,ru: 'статистика нетто активн инс netIOB' ,tr: 'netIOB istatistikleri' + ,hu: 'netIOB statisztika' } ,'temp basals must be rendered to display this report': { //hourlystats.js nl: 'tijdelijk basaal moet zichtbaar zijn voor dit rapport' @@ -1541,6 +1602,7 @@ function init() { , pl: 'Tymczasowa dawka podstawowa jest wymagana aby wyświetlić ten raport' ,ru: 'для этого отчета требуется прорисовка врем базалов' ,tr: 'Bu raporu görüntülemek için geçici bazal oluşturulmalıdır' + ,hu: 'Az átmeneti bazálnak meg kell lennie jelenítve az adott jelentls megtekintéséhez' } ,'Weekly success' : { cs: 'Statistika po týdnech' @@ -1566,6 +1628,7 @@ function init() { ,ko: '주간 통계' ,tr: 'Haftalık başarı' ,zh_cn: '每周统计' + ,hu: 'Heti sikeresség' } ,'No data available' : { cs: 'Žádná dostupná data' @@ -1591,6 +1654,7 @@ function init() { ,ko: '활용할 수 있는 데이터 없음' ,tr: 'Veri yok' ,zh_cn: '无可用数据' + ,hu: 'Nincs elérhető adat' } ,'Low' : { cs: 'Nízká' @@ -1616,6 +1680,7 @@ function init() { ,ko: '낮음' ,tr: 'Düşük' ,zh_cn: '低血糖' + ,hu: 'Alacsony' } ,'In Range' : { cs: 'V rozsahu' @@ -1641,6 +1706,7 @@ function init() { ,ko: '범위 안 ' ,tr: 'Hedef alanında' ,zh_cn: '范围内' + ,hu: 'Normális' } ,'Period' : { cs: 'Období' @@ -1666,6 +1732,7 @@ function init() { ,ko: '기간 ' ,tr: 'Periyot' ,zh_cn: '期间' + ,hu: 'Időszak' } ,'High' : { cs: 'Vysoká' @@ -1691,6 +1758,7 @@ function init() { ,ko: '높음' ,tr: 'Yüksek' ,zh_cn: '高血糖' + ,hu: 'Magas' } ,'Average' : { cs: 'Průměr' @@ -1716,6 +1784,7 @@ function init() { ,ko: '평균' ,tr: 'Ortalama' ,zh_cn: '平均' + ,hu: 'Átlagos' } ,'Low Quartile' : { cs: 'Nízký kvartil' @@ -1741,6 +1810,7 @@ function init() { ,ko: '낮은 4분위' ,tr: 'Alt Çeyrek' ,zh_cn: '下四分位数' + ,hu: 'Alacsony kvartil' } ,'Upper Quartile' : { cs: 'Vysoký kvartil' @@ -1766,6 +1836,7 @@ function init() { ,ko: '높은 4분위' ,tr: 'Üst Çeyrek' ,zh_cn: '上四分位数' + ,hu: 'Magas kvartil' } ,'Quartile' : { cs: 'Kvartil' @@ -1791,6 +1862,7 @@ function init() { ,ko: '4분위' ,tr: 'Çeyrek' ,zh_cn: '四分位数' + ,hu: 'Kvartil' } ,'Date' : { cs: 'Datum' @@ -1816,6 +1888,7 @@ function init() { ,ko: '날짜' ,tr: 'Tarih' ,zh_cn: '日期' + ,hu: 'Dátum' } ,'Normal' : { cs: 'Normální' @@ -1841,6 +1914,7 @@ function init() { ,ko: '보통' ,tr: 'Normal' ,zh_cn: '正常' + ,hu: 'Normális' } ,'Median' : { cs: 'Medián' @@ -1866,6 +1940,7 @@ function init() { ,ko: '중간값' ,tr: 'Orta Değer' ,zh_cn: '中值' + ,hu: 'Medián' } ,'Readings' : { cs: 'Záznamů' @@ -1891,6 +1966,7 @@ function init() { ,ko: '혈당' ,tr: 'Ölçüm' ,zh_cn: '读数' + ,hu: 'Értékek' } ,'StDev' : { cs: 'Směrodatná odchylka' @@ -1916,6 +1992,7 @@ function init() { ,ko: '표준 편차' ,tr: 'Standart Sapma' ,zh_cn: '标准偏差' + ,hu: 'Standard eltérés' } ,'Daily stats report' : { cs: 'Denní statistiky' @@ -1941,6 +2018,7 @@ function init() { ,ko: '일간 통계 보고서' ,tr: 'Günlük istatistikler raporu' ,zh_cn: '每日状态报表' + ,hu: 'Napi statisztikák' } ,'Glucose Percentile report' : { cs: 'Tabulka percentil glykémií' @@ -1966,6 +2044,7 @@ function init() { ,ko: '혈당 백분위 보고서' ,tr: 'Glikoz Yüzdelik raporu' ,zh_cn: '血糖百分位报表' + ,hu: 'Cukorszint percentil jelentés' } ,'Glucose distribution' : { cs: 'Rozložení glykémií' @@ -1991,6 +2070,7 @@ function init() { ,ko: '혈당 분포' ,tr: 'Glikoz dağılımı' ,zh_cn: '血糖分布' + ,hu: 'Cukorszint szétosztása' } ,'days total' : { cs: 'dní celkem' @@ -2016,6 +2096,7 @@ function init() { ,ko: '일 전체' ,tr: 'toplam gün' ,zh_cn: '天总计' + ,hu: 'nap összesen' } ,'Total per day' : { cs: 'dní celkem' @@ -2040,6 +2121,7 @@ function init() { ,ko: '하루 총량' ,tr: 'Günlük toplam' ,zh_cn: '天总计' + ,hu: 'Naponta összesen' } ,'Overall' : { cs: 'Celkem' @@ -2065,6 +2147,7 @@ function init() { ,ko: '전체' ,tr: 'Tüm' ,zh_cn: '概览' + ,hu: 'Összesen' } ,'Range' : { cs: 'Rozsah' @@ -2090,6 +2173,7 @@ function init() { ,ko: '범위' ,tr: 'Alan' ,zh_cn: '范围' + ,hu: 'Tartomány' } ,'% of Readings' : { cs: '% záznamů' @@ -2115,6 +2199,7 @@ function init() { ,ko: '수신된 혈당 비율(%)' ,tr: '% Okumaların' ,zh_cn: '%已读取' + ,hu: '% az értékeknek' } ,'# of Readings' : { cs: 'počet záznamů' @@ -2140,6 +2225,7 @@ function init() { ,ko: '수신된 혈당 개수(#)' ,tr: '# Okumaların' ,zh_cn: '#已读取' + ,hu: 'Olvasott értékek száma' } ,'Mean' : { cs: 'Střední hodnota' @@ -2165,6 +2251,7 @@ function init() { ,ko: '평균' ,tr: 'ortalama' ,zh_cn: '平均' + ,hu: 'Közép' } ,'Standard Deviation' : { cs: 'Standardní odchylka' @@ -2190,6 +2277,7 @@ function init() { ,ko: '표준 편차' ,tr: 'Standart Sapma' ,zh_cn: '标准偏差' + ,hu: 'Átlagos eltérés' } ,'Max' : { cs: 'Max' @@ -2215,6 +2303,7 @@ function init() { ,ko: '최대값' ,tr: 'Max' ,zh_cn: '最大值' + ,hu: 'Max' } ,'Min' : { cs: 'Min' @@ -2240,6 +2329,7 @@ function init() { ,ko: '최소값' ,tr: 'Min' ,zh_cn: '最小值' + ,hu: 'Min' } ,'A1c estimation*' : { cs: 'Předpokládané HBA1c*' @@ -2265,6 +2355,7 @@ function init() { ,ko: '예상 당화혈 색소' ,tr: 'Tahmini A1c *' ,zh_cn: '糖化血红蛋白估算' + ,hu: 'Megközelítőleges HbA1c' } ,'Weekly Success' : { cs: 'Týdenní úspěšnost' @@ -2290,6 +2381,7 @@ function init() { ,ko: '주간 통계' ,tr: 'Haftalık Başarı' ,zh_cn: '每周统计' + ,hu: 'Heti sikeresség' } ,'There is not sufficient data to run this report. Select more days.' : { cs: 'Není dostatek dat. Vyberte delší časové období.' @@ -2315,6 +2407,7 @@ function init() { ,ko: '이 보고서를 실행하기 위한 데이터가 충분하지 않습니다. 더 많은 날들을 선택해 주세요.' ,tr: 'Bu raporu çalıştırmak için yeterli veri yok. Daha fazla gün seçin.' ,zh_cn: '没有足够的数据生成报表,请选择更长时间段。' + ,hu: 'Nincs elég adat a jelentés elkészítéséhez. Válassz több napot.' } // food editor ,'Using stored API secret hash' : { @@ -2342,6 +2435,7 @@ function init() { ,tr: 'Kaydedilmiş API secret hash kullan' ,zh_cn: '使用已存储的API密钥哈希值' ,zh_tw: '使用已存儲的API密鑰哈希值' + ,hu: 'Az elmentett API hash jelszót használom' } ,'No API secret hash stored yet. You need to enter API secret.' : { cs: 'Není uložený žádný hash API hesla. Musíte zadat API heslo.' @@ -2368,6 +2462,7 @@ function init() { ,tr: 'Henüz bir API secret hash saklanmadı. API parolasını girmeniz gerekiyor.' ,zh_cn: '没有已存储的API密钥,请输入API密钥。' ,zh_tw: '沒有已存儲的API密鑰,請輸入API密鑰。' + ,hu: 'Még nem lett a titkos API hash elmentve. Add meg a titkos API jelszót' } ,'Database loaded' : { cs: 'Databáze načtena' @@ -2393,6 +2488,7 @@ function init() { ,ko: '데이터베이스 로드' ,tr: 'Veritabanı yüklendi' ,zh_cn: '数据库已载入' + ,hu: 'Adatbázis betöltve' } ,'Error: Database failed to load' : { cs: 'Chyba při načítání databáze' @@ -2418,6 +2514,7 @@ function init() { ,ko: '에러: 데이터베이스 로드 실패' ,tr: 'Hata: Veritabanı yüklenemedi' ,zh_cn: '错误:数据库载入失败' + ,hu: 'Hiba: Az adatbázist nem sikerült betölteni' } ,'Error' : { cs: 'Error' @@ -2443,6 +2540,7 @@ function init() { ,tr: 'Error' ,zh_cn: 'Error' ,zh_tw: 'Error' + ,hu: 'Hiba' } ,'Create new record' : { cs: 'Vytvořit nový záznam' @@ -2468,6 +2566,7 @@ function init() { ,ko: '새입력' ,tr: 'Yeni kayıt oluştur' ,zh_cn: '新增记录' + ,hu: 'Új bejegyzés' } ,'Save record' : { cs: 'Uložit záznam' @@ -2493,6 +2592,7 @@ function init() { ,ko: '저장' ,tr: 'Kayıtları kaydet' ,zh_cn: '保存记录' + ,hu: 'Bejegyzés mentése' } ,'Portions' : { cs: 'Porcí' @@ -2518,6 +2618,7 @@ function init() { ,ko: '부분' ,tr: 'Porsiyonlar' ,zh_cn: '部分' + ,hu: 'Porció' } ,'Unit' : { cs: 'Jedn' @@ -2543,6 +2644,7 @@ function init() { ,ko: '단위' ,tr: 'Birim' ,zh_cn: '单位' + ,hu: 'Egység' } ,'GI' : { cs: 'GI' @@ -2568,6 +2670,7 @@ function init() { ,ko: '혈당 지수' ,tr: 'GI-Glisemik İndeks' ,zh_cn: 'GI(血糖生成指数)' + ,hu: 'GI' } ,'Edit record' : { cs: 'Upravit záznam' @@ -2593,6 +2696,7 @@ function init() { ,ko: '편집기록' ,tr: 'Kaydı düzenle' ,zh_cn: '编辑记录' + ,hu: 'Bejegyzés szerkesztése' } ,'Delete record' : { cs: 'Smazat záznam' @@ -2618,6 +2722,7 @@ function init() { ,ko: '삭제기록' ,tr: 'Kaydı sil' ,zh_cn: '删除记录' + ,hu: 'Bejegyzés törlése' } ,'Move to the top' : { cs: 'Přesuň na začátek' @@ -2643,6 +2748,7 @@ function init() { ,ko: '맨처음으로 이동' ,tr: 'En üste taşı' ,zh_cn: '移至顶端' + ,hu: 'Áthelyezni az elejére' } ,'Hidden' : { cs: 'Skrytý' @@ -2668,6 +2774,7 @@ function init() { ,ko: '숨김' ,tr: 'Gizli' ,zh_cn: '隐藏' + ,hu: 'Elrejtett' } ,'Hide after use' : { cs: 'Skryj po použití' @@ -2693,6 +2800,7 @@ function init() { ,ko: '사용 후 숨김' ,tr: 'Kullandıktan sonra gizle' ,zh_cn: '使用后隐藏' + ,hu: 'Elrejteni használat után' } ,'Your API secret must be at least 12 characters long' : { cs: 'Vaše API heslo musí mít alespoň 12 znaků' @@ -2719,6 +2827,7 @@ function init() { ,tr: 'PI parolanız en az 12 karakter uzunluğunda olmalıdır' ,zh_cn: 'API密钥最少需要12个字符' ,zh_tw: 'API密鑰最少需要12個字符' + ,hu: 'Az API jelszó több mint 12 karakterből kell hogy álljon' } ,'Bad API secret' : { cs: 'Chybné API heslo' @@ -2745,6 +2854,7 @@ function init() { ,tr: 'Hatalı API parolası' ,zh_cn: 'API密钥错误' ,zh_tw: 'API密鑰錯誤' + ,hu: 'Helytelen API jelszó' } ,'API secret hash stored' : { cs: 'Hash API hesla uložen' @@ -2771,6 +2881,7 @@ function init() { ,tr: 'API secret hash parolası saklandı' ,zh_cn: 'API密钥已存储' ,zh_tw: 'API密鑰已存儲' + ,hu: 'API jelszó elmentve' } ,'Status' : { cs: 'Status' @@ -2796,6 +2907,7 @@ function init() { ,ko: '상태' ,tr: 'Durum' ,zh_cn: '状态' + ,hu: 'Állapot' } ,'Not loaded' : { cs: 'Nenačtený' @@ -2821,6 +2933,7 @@ function init() { ,ko: '로드되지 않음' ,tr: 'Yüklü değil' ,zh_cn: '未载入' + ,hu: 'Nincs betöltve' } ,'Food Editor' : { cs: 'Editor jídel' @@ -2846,6 +2959,7 @@ function init() { ,ko: '음식 편집' ,tr: 'Gıda Editörü' ,zh_cn: '食物编辑器' + ,hu: 'Étel szerkesztése' } ,'Your database' : { cs: 'Vaše databáze' @@ -2871,6 +2985,7 @@ function init() { ,ko: '당신의 데이터베이스' ,tr: 'Sizin Veritabanınız' ,zh_cn: '你的数据库' + ,hu: 'Ön adatbázisa' } ,'Filter' : { cs: 'Filtr' @@ -2896,6 +3011,7 @@ function init() { ,ko: '필터' ,tr: 'Filtre' ,zh_cn: '过滤器' + ,hu: 'Filter' } ,'Save' : { cs: 'Ulož' @@ -2922,6 +3038,7 @@ function init() { ,tr: 'Kaydet' ,zh_cn: '保存' ,zh_tw: '保存' + ,hu: 'Mentés' } ,'Clear' : { cs: 'Vymaž' @@ -2947,6 +3064,7 @@ function init() { ,ko: '취소' ,tr: 'Temizle' ,zh_cn: '清除' + ,hu: 'Kitöröl' } ,'Record' : { cs: 'Záznam' @@ -2972,6 +3090,7 @@ function init() { ,ko: '기록' ,tr: 'Kayıt' ,zh_cn: '记录' + ,hu: 'Bejegyzés' } ,'Quick picks' : { cs: 'Rychlý výběr' @@ -2997,6 +3116,7 @@ function init() { ,ko: '빠른 선택' ,tr: 'Hızlı seçim' ,zh_cn: '快速选择' + ,hu: 'Gyors választás' } ,'Show hidden' : { cs: 'Zobraz skryté' @@ -3022,16 +3142,21 @@ function init() { ,ko: '숨김 보기' ,tr: 'Gizli göster' ,zh_cn: '显示隐藏值' + ,hu: 'Eltakart mutatása' } ,'Your API secret or token' : { fi: 'API salaisuus tai avain' - , pl: 'Twój hash API lub token' + ,pl: 'Twój hash API lub token' ,ru: 'Ваш пароль API или код доступа ' + ,de: 'Deine API-Prüfsumme oder Token' + ,hu: 'Az API jelszo' } ,'Remember this device. (Do not enable this on public computers.)' : { fi: 'Muista tämä laite (Älä valitse julkisilla tietokoneilla)' , pl: 'Zapamiętaj to urządzenie (Nie używaj tej opcji korzystając z publicznych komputerów.)' ,ru: 'Запомнить это устройство (Не применяйте в общем доступе)' + ,de: 'An dieses Gerät erinnern. (Nicht auf öffentlichen Geräten verwenden)' + ,hu: 'A berendezés megjegyzése. (Csak saját berendezésen használd' } ,'Treatments' : { cs: 'Ošetření' @@ -3057,6 +3182,7 @@ function init() { ,ko: '관리' ,tr: 'Tedaviler' ,zh_cn: '操作' + ,hu: 'Kezelések' } ,'Time' : { cs: 'Čas' @@ -3083,6 +3209,7 @@ function init() { ,tr: 'Zaman' ,zh_cn: '时间' ,zh_tw: '時間' + ,hu: 'Idő' } ,'Event Type' : { cs: 'Typ události' @@ -3108,6 +3235,7 @@ function init() { ,ko: '입력 유형' ,tr: 'Etkinlik tipi' ,zh_cn: '事件类型' + ,hu: 'Esemény típusa' } ,'Blood Glucose' : { cs: 'Glykémie' @@ -3133,6 +3261,7 @@ function init() { ,ko: '혈당' ,tr: 'Kan Şekeri' ,zh_cn: '血糖值' + ,hu: 'Vércukor szint' } ,'Entered By' : { cs: 'Zadal' @@ -3158,6 +3287,7 @@ function init() { ,ko: '입력 내용' ,tr: 'Tarafından girildi' ,zh_cn: '输入人' + ,hu: 'Beírta' } ,'Delete this treatment?' : { cs: 'Vymazat toto ošetření?' @@ -3183,6 +3313,7 @@ function init() { ,ko: '이 대처를 지울까요?' ,tr: 'Bu tedaviyi sil?' ,zh_cn: '删除这个操作?' + ,hu: 'Kezelés törlése?' } ,'Carbs Given' : { cs: 'Sacharidů' @@ -3208,6 +3339,7 @@ function init() { ,ko: '탄수화물 요구량' ,tr: 'Karbonhidrat Verilen' ,zh_cn: '碳水化合物量' + ,hu: 'Szénhidrátok' } ,'Inzulin Given' : { cs: 'Inzulínu' @@ -3233,6 +3365,7 @@ function init() { ,ko: '인슐린 요구량' ,tr: 'İnsülin Verilen' ,zh_cn: '胰岛素输注' + ,hu: 'Beadott inzulin' } ,'Event Time' : { cs: 'Čas události' @@ -3258,6 +3391,7 @@ function init() { ,ko: '입력 시간' ,tr: 'Etkinliğin zamanı' ,zh_cn: '事件时间' + ,hu: 'Időpont' } ,'Please verify that the data entered is correct' : { cs: 'Prosím zkontrolujte, zda jsou údaje zadány správně' @@ -3283,6 +3417,7 @@ function init() { ,ko: '입력한 데이터가 정확한지 확인해 주세요.' ,tr: 'Lütfen girilen verilerin doğru olduğunu kontrol edin.' ,zh_cn: '请验证输入的数据是否正确' + ,hu: 'Kérlek ellenőrizd, hogy az adatok helyesek.' } ,'BG' : { cs: 'Glykémie' @@ -3308,6 +3443,7 @@ function init() { ,ko: '혈당' ,tr: 'KŞ' ,zh_cn: '血糖' + ,hu: 'Cukorszint' } ,'Use BG correction in calculation' : { cs: 'Použij korekci na glykémii' @@ -3333,6 +3469,7 @@ function init() { ,ko: '계산에 보정된 혈당을 사용하세요.' ,tr: 'Hesaplamada KŞ düzeltmesini kullan' ,zh_cn: '使用血糖值修正计算' + ,hu: 'Használj korekciót a számításban' } ,'BG from CGM (autoupdated)' : { cs: 'Glykémie z CGM (automaticky aktualizovaná)' @@ -3358,6 +3495,7 @@ function init() { ,ko: 'CGM 혈당(자동 업데이트)' ,tr: 'CGM den KŞ (otomatik güncelleme)' ,zh_cn: 'CGM(连续血糖监测)测量的血糖值(自动更新)' + ,hu: 'Cukorszint a CGM-ből (Automatikus frissítés)' } ,'BG from meter' : { cs: 'Glykémie z glukoměru' @@ -3383,6 +3521,7 @@ function init() { ,ko: '혈당 측정기에서의 혈당' ,tr: 'Glikometre KŞ' ,zh_cn: '血糖仪测量的血糖值' + ,hu: 'Cukorszint a merőből' } ,'Manual BG' : { cs: 'Ručně zadaná glykémie' @@ -3408,6 +3547,7 @@ function init() { ,ko: '수동 입력 혈당' ,tr: 'Manuel KŞ' ,zh_cn: '手动输入的血糖值' + ,hu: 'Kézi cukorszint' } ,'Quickpick' : { cs: 'Rychlý výběr' @@ -3433,6 +3573,7 @@ function init() { ,ko: '빠른 선택' ,tr: 'Hızlı seçim' ,zh_cn: '快速选择' + ,hu: 'Gyors választás' } ,'or' : { cs: 'nebo' @@ -3458,6 +3599,7 @@ function init() { ,ko: '또는' ,tr: 'veya' ,zh_cn: '或' + ,hu: 'vagy' } ,'Add from database' : { cs: 'Přidat z databáze' @@ -3483,6 +3625,7 @@ function init() { ,ko: '데이터베이스로 부터 추가' ,tr: 'Veritabanından ekle' ,zh_cn: '从数据库增加' + ,hu: 'Hozzáadás adatbázisból' } ,'Use carbs correction in calculation' : { cs: 'Použij korekci na sacharidy' @@ -3508,6 +3651,7 @@ function init() { ,ko: '계산에 보정된 탄수화물을 사용하세요.' ,tr: 'Hesaplamada karbonhidrat düzeltmesini kullan' ,zh_cn: '使用碳水化合物修正计算结果' + ,hu: 'Használj szénhidrát korekciót a számításban' } ,'Use COB correction in calculation' : { cs: 'Použij korekci na COB' @@ -3533,6 +3677,7 @@ function init() { ,ko: '계산에 보정된 COB를 사용하세요.' ,tr: 'Hesaplamada COB aktif karbonhidrat düzeltmesini kullan' ,zh_cn: '使用COB(活性碳水化合物)修正计算结果' + ,hu: 'Használj COB korrekciót a számításban' } ,'Use IOB in calculation' : { cs: 'Použij IOB ve výpočtu' @@ -3558,6 +3703,7 @@ function init() { ,ko: '계산에 IOB를 사용하세요.' ,tr: 'Hesaplamada IOB aktif insülin düzeltmesini kullan' ,zh_cn: '使用IOB(活性胰岛素)修正计算结果' + ,hu: 'Használj IOB kalkulációt' } ,'Other correction' : { cs: 'Jiná korekce' @@ -3583,6 +3729,7 @@ function init() { ,ko: '다른 보정' ,tr: 'Diğer düzeltme' ,zh_cn: '其它修正' + ,hu: 'Egyébb korrekció' } ,'Rounding' : { cs: 'Zaokrouhlení' @@ -3608,6 +3755,7 @@ function init() { ,ko: '라운딩' ,tr: 'yuvarlama' ,zh_cn: '取整' + ,hu: 'Kerekítés' } ,'Enter insulin correction in treatment' : { cs: 'Zahrň inzulín do záznamu ošetření' @@ -3633,6 +3781,7 @@ function init() { ,ko: '대처를 위해 보정된 인슐린을 입력하세요.' ,tr: 'Tedavide insülin düzeltmesini girin' ,zh_cn: '在操作中输入胰岛素修正' + ,hu: 'Add be az inzulin korrekciót a kezeléshez' } ,'Insulin needed' : { cs: 'Potřebný inzulín' @@ -3658,6 +3807,7 @@ function init() { ,ko: '인슐린 필요' ,tr: 'İnsülin gerekli' ,zh_cn: '需要的胰岛素量' + ,hu: 'Inzulin szükséges' } ,'Carbs needed' : { cs: 'Potřebné sach' @@ -3683,6 +3833,7 @@ function init() { ,ko: '탄수화물 필요' ,tr: 'Karbonhidrat gerekli' ,zh_cn: '需要的碳水量' + ,hu: 'Szenhidrát szükséges' } ,'Carbs needed if Insulin total is negative value' : { cs: 'Chybějící sacharidy v případě, že výsledek je záporný' @@ -3708,6 +3859,7 @@ function init() { ,ko: '인슐린 전체가 마이너스 값이면 탄수화물이 필요합니다.' ,tr: 'Toplam insülin negatif değer olduğunda karbonhidrat gereklidir' ,zh_cn: '如果胰岛素总量为负时所需的碳水化合物量' + ,hu: 'Szénhidrát szükséges ha az összes inzulin negatív érték' } ,'Basal rate' : { cs: 'Bazál' @@ -3733,6 +3885,7 @@ function init() { ,ko: 'Basal 단위' ,tr: 'Basal oranı' ,zh_cn: '基础率' + ,hu: 'Bazál arány' } ,'60 minutes earlier' : { cs: '60 min předem' @@ -3758,6 +3911,7 @@ function init() { ,ko: '60분 더 일찍' ,tr: '60 dak. önce' //erken önce ??? ,zh_cn: '60分钟前' + ,hu: '60 perccel korábban' } ,'45 minutes earlier' : { cs: '45 min předem' @@ -3783,6 +3937,7 @@ function init() { ,ko: '45분 더 일찍' ,tr: '45 dak. önce' ,zh_cn: '45分钟前' + ,hu: '45 perccel korábban' } ,'30 minutes earlier' : { cs: '30 min předem' @@ -3808,6 +3963,7 @@ function init() { ,ko: '30분 더 일찍' ,tr: '30 dak. önce' ,zh_cn: '30分钟前' + ,hu: '30 perccel korábban' } ,'20 minutes earlier' : { cs: '20 min předem' @@ -3833,6 +3989,7 @@ function init() { ,ko: '20분 더 일찍' ,tr: '20 dak. önce' ,zh_cn: '20分钟前' + ,hu: '20 perccel korábban' } ,'15 minutes earlier' : { cs: '15 min předem' @@ -3858,6 +4015,7 @@ function init() { ,ko: '15분 더 일찍' ,tr: '15 dak. önce' ,zh_cn: '15分钟前' + ,hu: '15 perccel korábban' } ,'Time in minutes' : { cs: 'Čas v minutách' @@ -3882,6 +4040,7 @@ function init() { ,ko: '분' ,tr: 'Dakika cinsinden süre' ,zh_cn: '1分钟前' + ,hu: 'Idő percekben' } ,'15 minutes later' : { cs: '15 min po' @@ -3907,6 +4066,7 @@ function init() { ,ko: '15분 더 나중에' ,tr: '15 dak. sonra' //sonra daha sonra ,zh_cn: '15分钟后' + ,hu: '15 perccel később' } ,'20 minutes later' : { cs: '20 min po' @@ -3932,6 +4092,7 @@ function init() { ,ko: '20분 더 나중에' ,tr: '20 dak. sonra' ,zh_cn: '20分钟后' + ,hu: '20 perccel később' } ,'30 minutes later' : { cs: '30 min po' @@ -3957,6 +4118,7 @@ function init() { ,ko: '30분 더 나중에' ,tr: '30 dak. sonra' ,zh_cn: '30分钟后' + ,hu: '30 perccel kesőbb' } ,'45 minutes later' : { cs: '45 min po' @@ -3982,6 +4144,7 @@ function init() { ,ko: '45분 더 나중에' ,tr: '45 dak. sonra' ,zh_cn: '45分钟后' + ,hu: '45 perccel később' } ,'60 minutes later' : { cs: '60 min po' @@ -4007,6 +4170,7 @@ function init() { ,ko: '60분 더 나중에' ,tr: '60 dak. sonra' ,zh_cn: '60分钟后' + ,hu: '60 perccel később' } ,'Additional Notes, Comments' : { cs: 'Dalši poznámky, komentáře' @@ -4032,6 +4196,7 @@ function init() { ,ko: '추가 메모' ,tr: 'Ek Notlar, Yorumlar' ,zh_cn: '备注' + ,hu: 'Feljegyzések, hozzászólások' } ,'RETRO MODE' : { cs: 'V MINULOSTI' @@ -4057,6 +4222,7 @@ function init() { ,ko: 'PETRO MODE' ,tr: 'RETRO MODE' ,zh_cn: '历史模式' + ,hu: 'RETRO mód' } ,'Now' : { cs: 'Nyní' @@ -4082,6 +4248,7 @@ function init() { ,ko: '현재' ,tr: 'Şimdi' ,zh_cn: '现在' + ,hu: 'Most' } ,'Other' : { cs: 'Jiný' @@ -4107,6 +4274,7 @@ function init() { ,ko: '다른' ,tr: 'Diğer' ,zh_cn: '其它' + ,hu: 'Más' } ,'Submit Form' : { cs: 'Odeslat formulář' @@ -4132,6 +4300,7 @@ function init() { ,ko: '양식 제출' ,tr: 'Formu gönder' ,zh_cn: '提交' + ,hu: 'Elküldés' } ,'Profile Editor' : { cs: 'Editor profilu' @@ -4158,6 +4327,7 @@ function init() { ,tr: 'Profil Düzenleyicisi' ,zh_cn: '配置文件编辑器' ,zh_tw: '配置文件編輯器' + ,hu: 'Profil Szerkesztő' } ,'Reports' : { cs: 'Výkazy' @@ -4184,6 +4354,7 @@ function init() { ,tr: 'Raporlar' ,zh_cn: '生成报表' ,zh_tw: '生成報表' + ,hu: 'Jelentések' } ,'Add food from your database' : { cs: 'Přidat jidlo z Vaší databáze' @@ -4209,6 +4380,7 @@ function init() { ,ko: '데이터베이스에서 음식을 추가하세요.' ,tr: 'Veritabanınızdan yemek ekleyin' ,zh_cn: '从数据库增加食物' + ,hu: 'Étel hozzáadása az adatbázisból' } ,'Reload database' : { cs: 'Znovu nahraj databázi' @@ -4234,6 +4406,7 @@ function init() { ,ko: '데이터베이스 재로드' ,tr: 'Veritabanını yeniden yükle' ,zh_cn: '重新载入数据库' + ,hu: 'Adatbázis újratöltése' } ,'Add' : { cs: 'Přidej' @@ -4259,6 +4432,7 @@ function init() { ,ko: '추가' ,tr: 'Ekle' ,zh_cn: '增加' + ,hu: 'Hozzáadni' } ,'Unauthorized' : { cs: 'Neautorizováno' @@ -4285,6 +4459,7 @@ function init() { ,tr: 'Yetkisiz' ,zh_cn: '未授权' ,zh_tw: '未授權' + ,hu: 'Nincs autorizávla' } ,'Entering record failed' : { cs: 'Vložení záznamu selhalo' @@ -4310,6 +4485,7 @@ function init() { ,ko: '입력 실패' ,tr: 'Kayıt girişi başarısız oldu' ,zh_cn: '输入记录失败' + ,hu: 'Hozzáadás nem sikerült' } ,'Device authenticated' : { cs: 'Zařízení ověřeno' @@ -4336,6 +4512,7 @@ function init() { ,tr: 'Cihaz kimliği doğrulandı' ,zh_cn: '设备已认证' ,zh_tw: '設備已認證' + ,hu: 'Berendezés hitelesítve' } ,'Device not authenticated' : { cs: 'Zařízení není ověřeno' @@ -4362,6 +4539,7 @@ function init() { ,tr: 'Cihaz kimliği doğrulanmamış' ,zh_cn: '设备未认证' ,zh_tw: '設備未認證' + ,hu: 'Berendezés nincs hitelesítve' } ,'Authentication status' : { cs: 'Stav ověření' @@ -4388,6 +4566,7 @@ function init() { ,tr: 'Kimlik doğrulama durumu' ,zh_cn: '认证状态' ,zh_tw: '認證狀態' + ,hu: 'Hitelesítés állapota' } ,'Authenticate' : { cs: 'Ověřit' @@ -4414,6 +4593,7 @@ function init() { ,tr: 'Kimlik doğrulaması' ,zh_cn: '认证' ,zh_tw: '認證' + ,hu: 'Hitelesítés' } ,'Remove' : { cs: 'Vymazat' @@ -4440,6 +4620,7 @@ function init() { ,tr: 'Kaldır' ,zh_cn: '取消' ,zh_tw: '取消' + ,hu: 'Eltávolítani' } ,'Your device is not authenticated yet' : { cs: 'Toto zařízení nebylo dosud ověřeno' @@ -4466,6 +4647,7 @@ function init() { ,tr: 'Cihazınız henüz doğrulanmamış' ,zh_cn: '此设备还未进行认证' ,zh_tw: '這個設備還未進行認證' + ,hu: 'A berendezés még nincs hitelesítve' } ,'Sensor' : { cs: 'Senzor' @@ -4491,6 +4673,7 @@ function init() { ,ko: '센서' ,tr: 'Sensor' ,zh_cn: 'CGM探头' + ,hu: 'Szenzor' } ,'Finger' : { cs: 'Glukoměr' @@ -4516,6 +4699,7 @@ function init() { ,ko: '손가락' ,tr: 'Parmak' ,zh_cn: '手指' + ,hu: 'Új' } ,'Manual' : { cs: 'Ručně' @@ -4541,6 +4725,7 @@ function init() { ,ko: '수' ,tr: 'Elle' ,zh_cn: '手动' + ,hu: 'Kézi' } ,'Scale' : { cs: 'Měřítko' @@ -4567,6 +4752,7 @@ function init() { ,tr: 'Ölçek' ,zh_cn: '函数' ,zh_tw: '函數' + ,hu: 'Mérték' } ,'Linear' : { cs: 'Lineární' @@ -4593,6 +4779,7 @@ function init() { ,tr: 'Doğrusal' //çizgisel ,zh_cn: '线性' ,zh_tw: '線性' + ,hu: 'Lineáris' } ,'Logarithmic' : { cs: 'Logaritmické' @@ -4619,6 +4806,7 @@ function init() { ,tr: 'Logaritmik' ,zh_cn: '对数' ,zh_tw: '對數' + ,hu: 'Logaritmikus' } ,'Logarithmic (Dynamic)' : { cs: 'Logaritmické (Dynamické)' @@ -4645,6 +4833,7 @@ function init() { ,tr: 'Logaritmik (Dinamik)' ,zh_cn: '对数(动态)' ,zh_tw: '對數(動態)' + ,hu: 'Logaritmikus (Dinamikus)' } ,'Insulin-on-Board' : { cs: 'IOB' @@ -4671,6 +4860,7 @@ function init() { ,tr: 'Aktif İnsülin (IOB)' ,zh_cn: '活性胰岛素(IOB)' ,zh_tw: '活性胰島素(IOB)' + ,hu: 'Aktív inzulin (IOB)' } ,'Carbs-on-Board' : { cs: 'COB' @@ -4697,6 +4887,7 @@ function init() { ,tr: 'Aktif Karbonhidrat (COB)' ,zh_cn: '活性碳水化合物(COB)' ,zh_tw: '活性碳水化合物(COB)' + ,hu: 'Aktív szénhidrát (COB)' } ,'Bolus Wizard Preview' : { cs: 'BWP-Náhled bolusového kalk.' @@ -4723,6 +4914,7 @@ function init() { ,tr: 'Bolus hesaplama Sihirbazı Önizlemesi (BWP)' //İnsülin etkinlik süresi hesaplaması ,zh_cn: '大剂量向导预览(BWP)' ,zh_tw: '大劑量嚮導預覽(BWP)' + ,hu: 'Bolus Varázsló' } ,'Value Loaded' : { cs: 'Hodnoty načteny' @@ -4749,6 +4941,7 @@ function init() { ,tr: 'Yüklenen Değer' ,zh_cn: '数值已读取' ,zh_tw: '數值已讀取' + ,hu: 'Érték betöltve' } ,'Cannula Age' : { cs: 'CAGE-Stáří kanyly' @@ -4775,6 +4968,7 @@ function init() { ,tr: 'Kanül yaşı' ,zh_cn: '管路使用时间(CAGE)' ,zh_tw: '管路使用時間(CAGE)' + ,hu: 'Kanula élettartalma (CAGE)' } ,'Basal Profile' : { cs: 'Bazál' @@ -4801,6 +4995,7 @@ function init() { ,tr: 'Bazal Profil' ,zh_cn: '基础率配置文件' ,zh_tw: '基礎率配置文件' + ,hu: 'Bazál profil' } ,'Silence for 30 minutes' : { cs: 'Ztlumit na 30 minut' @@ -4827,6 +5022,7 @@ function init() { ,tr: '30 dakika sessizlik' ,zh_cn: '静音30分钟' ,zh_tw: '靜音30分鐘' + ,hu: 'Lehalkítás 30 percre' } ,'Silence for 60 minutes' : { cs: 'Ztlumit na 60 minut' @@ -4853,7 +5049,8 @@ function init() { ,tr: '60 dakika sessizlik' ,zh_cn: '静音60分钟' ,zh_tw: '靜音60分鐘' - } + ,hu: 'Lehalkítás 60 percre' + } ,'Silence for 90 minutes' : { cs: 'Ztlumit na 90 minut' ,he: 'השתק לתשעים דקות' @@ -4879,7 +5076,8 @@ function init() { ,tr: '90 dakika sessizlik' ,zh_cn: '静音90分钟' ,zh_tw: '靜音90分鐘' - } + ,hu: 'Lehalkítás 90 percre' + } ,'Silence for 120 minutes' : { cs: 'Ztlumit na 120 minut' ,he: 'השתק לשעתיים' @@ -4905,7 +5103,8 @@ function init() { ,tr: '120 dakika sessizlik' ,zh_cn: '静音2小时' ,zh_tw: '靜音2小時' - } + ,hu: 'Lehalkítás 120 percre' + } ,'Settings' : { cs: 'Nastavení' ,he: 'הגדרות' @@ -4931,6 +5130,7 @@ function init() { ,tr: 'Ayarlar' ,zh_cn: '设置' ,zh_tw: '設置' + ,hu: 'Beállítások' } ,'Units' : { cs: 'Jednotky' @@ -4956,6 +5156,7 @@ function init() { ,tr: 'Birim' //Birim Ünite ,zh_cn: '计量单位' ,zh_tw: '计量單位' + ,hu: 'Egységek' } ,'Date format' : { cs: 'Formát datumu' @@ -4982,6 +5183,7 @@ function init() { ,tr: 'Veri formatı' ,zh_cn: '时间格式' ,zh_tw: '時間格式' + ,hu: 'Időformátum' } ,'12 hours' : { cs: '12 hodin' @@ -5008,6 +5210,7 @@ function init() { ,tr: '12 saat' ,zh_cn: '12小时制' ,zh_tw: '12小時制' + ,hu: '12 óra' } ,'24 hours' : { cs: '24 hodin' @@ -5034,6 +5237,7 @@ function init() { ,tr: '24 saat' ,zh_cn: '24小时制' ,zh_tw: '24小時制' + ,hu: '24 óra' } ,'Log a Treatment' : { cs: 'Záznam ošetření' @@ -5059,6 +5263,7 @@ function init() { ,ko: 'Treatment 로그' ,tr: 'Tedaviyi günlüğe kaydet' ,zh_cn: '记录操作' + ,hu: 'Kezelés bejegyzése' } ,'BG Check' : { cs: 'Kontrola glykémie' @@ -5084,6 +5289,7 @@ function init() { ,ko: '혈당 체크' ,tr: 'KŞ Kontol' ,zh_cn: '测量血糖' + ,hu: 'Cukorszint ellenőrzés' } ,'Meal Bolus' : { cs: 'Bolus na jídlo' @@ -5109,6 +5315,7 @@ function init() { ,ko: '식사 인슐린' ,tr: 'Yemek bolus' ,zh_cn: '正餐大剂量' + ,hu: 'Étel bólus' } ,'Snack Bolus' : { cs: 'Bolus na svačinu' @@ -5134,6 +5341,7 @@ function init() { ,ko: '스넥 인슐린' ,tr: 'Aperatif (Snack) Bolus' ,zh_cn: '加餐大剂量' + ,hu: 'Tízórai/Uzsonna bólus' } ,'Correction Bolus' : { cs: 'Bolus na glykémii' @@ -5159,6 +5367,7 @@ function init() { ,ko: '수정 인슐린' ,tr: 'Düzeltme Bolusu' ,zh_cn: '临时大剂量' + ,hu: 'Korrekciós bólus' } ,'Carb Correction' : { cs: 'Přídavek sacharidů' @@ -5184,6 +5393,7 @@ function init() { ,ko: '탄수화물 수정' ,tr: 'Karbonhidrat Düzeltme' ,zh_cn: '碳水修正' + ,hu: 'Szénhidrát korrekció' } ,'Note' : { cs: 'Poznámka' @@ -5209,6 +5419,7 @@ function init() { ,ko: '메모' ,tr: 'Not' ,zh_cn: '备忘' + ,hu: 'Jegyzet' } ,'Question' : { cs: 'Otázka' @@ -5234,6 +5445,7 @@ function init() { ,ko: '질문' ,tr: 'Soru' ,zh_cn: '问题' + ,hu: 'Kérdés' } ,'Exercise' : { cs: 'Cvičení' @@ -5259,6 +5471,7 @@ function init() { ,ko: '운동' ,tr: 'Egzersiz' ,zh_cn: '运动' + ,hu: 'Edzés' } ,'Pump Site Change' : { cs: 'Výměna setu' @@ -5284,6 +5497,7 @@ function init() { ,ko: '펌프 위치 변경' ,tr: 'Pompa Kanül değişimi' ,zh_cn: '更换胰岛素输注部位' + ,hu: 'Pumpa szett csere' } ,'CGM Sensor Start' : { cs: 'Spuštění sensoru' @@ -5309,6 +5523,7 @@ function init() { ,ko: 'CGM 센서 시작' ,tr: 'CGM Sensörü Başlat' ,zh_cn: '启动CGM(连续血糖监测)探头' + ,hu: 'CGM Szenzor Indítása' } ,'CGM Sensor Stop' : { cs: 'CGM Sensor Stop' @@ -5334,6 +5549,7 @@ function init() { ,ko: 'CGM Sensor Stop' ,tr: 'CGM Sensor Stop' ,zh_cn: 'CGM Sensor Stop' + ,hu: 'CGM Szenzor Leállítása' } ,'CGM Sensor Insert' : { cs: 'Výměna sensoru' @@ -5359,6 +5575,7 @@ function init() { ,ko: 'CGM 센서 삽입' ,tr: 'CGM Sensor yerleştir' ,zh_cn: '植入CGM(连续血糖监测)探头' + ,hu: 'CGM Szenzor Csere' } ,'Dexcom Sensor Start' : { cs: 'Spuštění sensoru' @@ -5384,7 +5601,8 @@ function init() { ,ko: 'Dexcom 센서 시작' ,tr: 'Dexcom Sensör Başlat' ,zh_cn: '启动Dexcom探头' - } + ,hu: 'Dexcom Szenzor Indítása' + } ,'Dexcom Sensor Change' : { cs: 'Výměna sensoru' ,de: 'Dexcom Sensor Wechsel' @@ -5409,7 +5627,8 @@ function init() { ,ko: 'Dexcom 센서 교체' ,tr: 'Dexcom Sensör değiştir' ,zh_cn: '更换Dexcom探头' - } + ,hu: 'Dexcom Szenzor Csere' + } ,'Insulin Cartridge Change' : { cs: 'Výměna inzulínu' ,de: 'Insulin Ampullenwechsel' @@ -5434,6 +5653,7 @@ function init() { ,ko: '인슐린 카트리지 교체' ,tr: 'İnsülin rezervuar değişimi' ,zh_cn: '更换胰岛素储液器' + ,hu: 'Inzulin Tartály Csere' } ,'D.A.D. Alert' : { cs: 'D.A.D. Alert' @@ -5459,6 +5679,7 @@ function init() { ,ko: 'D.A.D(Diabetes Alert Dog) 알림' ,tr: 'D.A.D(Diabetes Alert Dog)' ,zh_cn: 'D.A.D(低血糖通报犬)警告' + ,hu: 'D.A.D Figyelmeztetés' } ,'Glucose Reading' : { cs: 'Hodnota glykémie' @@ -5483,6 +5704,7 @@ function init() { ,ko: '혈당 읽기' ,tr: 'Glikoz Değeri' ,zh_cn: '血糖数值' + ,hu: 'Vércukorszint Érték' } ,'Measurement Method' : { cs: 'Metoda měření' @@ -5508,6 +5730,7 @@ function init() { ,ko: '측정 방법' ,tr: 'Ölçüm Metodu' ,zh_cn: '测量方法' + ,hu: 'Cukorszint mérés metódusa' } ,'Meter' : { cs: 'Glukoměr' @@ -5533,6 +5756,7 @@ function init() { ,ko: '혈당 측정기' ,tr: 'Glikometre' ,zh_cn: '血糖仪' + ,hu: 'Cukorszint mérő' } ,'Insulin Given' : { cs: 'Inzulín' @@ -5558,6 +5782,7 @@ function init() { ,ko: '인슐린 요구량' ,tr: 'Verilen İnsülin' ,zh_cn: '胰岛素输注量' + ,hu: 'Inzulin Beadva' } ,'Amount in grams' : { cs: 'Množství v gramech' @@ -5583,6 +5808,7 @@ function init() { ,ko: '합계(grams)' ,tr: 'Gram cinsinden miktar' ,zh_cn: '总量(g)' + ,hu: 'Adag grammokban (g)' } ,'Amount in units' : { cs: 'Množství v jednotkách' @@ -5608,6 +5834,7 @@ function init() { ,ko: '합계(units)' ,tr: 'Birim miktarı' ,zh_cn: '总量(U)' + ,hu: 'Adag egységekben' } ,'View all treatments' : { cs: 'Zobraz všechny ošetření' @@ -5633,6 +5860,7 @@ function init() { ,ko: '모든 treatments 보기' ,tr: 'Tüm tedavileri görüntüle' ,zh_cn: '查看所有操作' + ,hu: 'Összes kezelés mutatása' } ,'Enable Alarms' : { cs: 'Povolit alarmy' @@ -5659,6 +5887,7 @@ function init() { ,tr: 'Alarmları Etkinleştir' ,zh_cn: '启用报警' ,zh_tw: '啟用報警' + ,hu: 'Figyelmeztetők bekapcsolása' } ,'Pump Battery Change' : { nl: 'Pompbatterij vervangen' @@ -5672,6 +5901,7 @@ function init() { ,pl: 'Zmiana baterii w pompie' ,ru: 'замена батареи помпы' ,tr: 'Pompa pil değişimi' + ,hu: 'Pumpa elem csere' } ,'Pump Battery Low Alarm' : { nl: 'Pompbatterij bijna leeg Alarm' @@ -5685,6 +5915,7 @@ function init() { ,pl: 'Alarm! Niski poziom baterii w pompie' ,ru: 'Внимание! низкий заряд батареи помпы' ,tr: 'Pompa Düşük pil alarmı' + ,hu: 'Alacsony pumpa töltöttség figyelmeztetés' } ,'Pump Battery change overdue!' : { // batteryage.js nl: 'Pompbatterij moet vervangen worden!' @@ -5698,6 +5929,7 @@ function init() { , pl: 'Bateria pompy musi być wymieniona!' ,ru: 'пропущен срок замены батареи!' ,tr: 'Pompa pil değişimi gecikti!' + ,hu: 'A pumpa eleme cserére szorul' } ,'When enabled an alarm may sound.' : { cs: 'Při povoleném alarmu zní zvuk' @@ -5724,6 +5956,7 @@ function init() { ,tr: 'Etkinleştirilirse, alarm çalar.' ,zh_cn: '启用后可发出声音报警' ,zh_tw: '啟用後可發出聲音報警' + ,hu: 'Bekapcsoláskor hang figyelmeztetés várható' } ,'Urgent High Alarm' : { cs: 'Urgentní vysoká glykémie' @@ -5750,6 +5983,7 @@ function init() { ,tr: 'Acil Yüksek Alarm' //Dikkat yüksek alarm ,zh_cn: '血糖过高报警' ,zh_tw: '血糖過高報警' + ,hu: 'Nagyon magas cukorszint figyelmeztetés' } ,'High Alarm' : { cs: 'Vysoká glykémie' @@ -5776,6 +6010,7 @@ function init() { ,tr: 'Yüksek Alarmı' ,zh_cn: '高血糖报警' ,zh_tw: '高血糖報警' + ,hu: 'Magas cukorszint fegyelmeztetés' } ,'Low Alarm' : { cs: 'Nízká glykémie' @@ -5802,6 +6037,7 @@ function init() { ,tr: 'Düşük Alarmı' ,zh_cn: '低血糖报警' ,zh_tw: '低血糖報警' + ,hu: 'Alacsony cukorszint figyelmeztetés' } ,'Urgent Low Alarm' : { cs: 'Urgentní nízká glykémie' @@ -5828,6 +6064,7 @@ function init() { ,tr: 'Acil Düşük Alarmı' ,zh_cn: '血糖过低报警' ,zh_tw: '血糖過低報警' + ,hu: 'Nagyon alacsony cukorszint figyelmeztetés' } ,'Stale Data: Warn' : { cs: 'Zastaralá data' @@ -5854,6 +6091,7 @@ function init() { ,tr: 'Eski Veri: Uyarı' //Uyarı: veri artık geçerli değil ,zh_cn: '数据过期:提醒' ,zh_tw: '數據過期:提醒' + ,hu: 'Figyelmeztetés: Az adatok öregnek tűnnek' } ,'Stale Data: Urgent' : { cs: 'Zastaralá data urgentní' @@ -5880,6 +6118,7 @@ function init() { ,tr: 'Eski Veri: Acil' ,zh_cn: '数据过期:警告' ,zh_tw: '數據過期:警告' + ,hu: 'Figyelmeztetés: Az adatok nagyon öregnek tűnnek' } ,'mins' : { cs: 'min' @@ -5906,6 +6145,7 @@ function init() { ,tr: 'dk.' ,zh_cn: '分' ,zh_tw: '分' + ,hu: 'perc' } ,'Night Mode' : { cs: 'Noční mód' @@ -5932,6 +6172,7 @@ function init() { ,tr: 'Gece Modu' ,zh_cn: '夜间模式' ,zh_tw: '夜間模式' + ,hu: 'Éjjeli üzemmód' } ,'When enabled the page will be dimmed from 10pm - 6am.' : { cs: 'Když je povoleno, obrazovka je ztlumena 22:00 - 6:00' @@ -5958,6 +6199,7 @@ function init() { ,tr: 'Etkinleştirildiğinde, ekran akşam 22\'den sabah 6\'ya kadar kararır.' ,zh_cn: '启用后将在夜间22点至早晨6点降低页面亮度' ,zh_tw: '啟用後將在夜間22點至早晨6點降低頁面亮度' + ,hu: 'Ezt bekapcsolva a képernyő halványabb lesz 22-től 6-ig' } ,'Enable' : { cs: 'Povoleno' @@ -5984,6 +6226,7 @@ function init() { ,tr: 'Etkinleştir' ,zh_cn: '启用' ,zh_tw: '啟用' + ,hu: 'Engedélyezve' } ,'Show Raw BG Data' : { cs: 'Zobraz RAW data' @@ -6010,6 +6253,7 @@ function init() { ,tr: 'Ham KŞ verilerini göster' ,zh_cn: '显示原始血糖数据' ,zh_tw: '顯示原始血糖數據' + ,hu: 'Nyers BG adatok mutatása' } ,'Never' : { cs: 'Nikdy' @@ -6036,6 +6280,7 @@ function init() { ,tr: 'Hiçbir zaman' //Asla ,zh_cn: '不显示' ,zh_tw: '不顯示' + ,hu: 'Soha' } ,'Always' : { cs: 'Vždy' @@ -6062,6 +6307,7 @@ function init() { ,tr: 'Her zaman' ,zh_cn: '一直显示' ,zh_tw: '一直顯示' + ,hu: 'Mindíg' } ,'When there is noise' : { cs: 'Při šumu' @@ -6088,6 +6334,7 @@ function init() { ,tr: 'Gürültü olduğunda' ,zh_cn: '当有噪声时显示' ,zh_tw: '當有噪聲時顯示' + ,hu: 'Ha zavar van:' } ,'When enabled small white dots will be displayed for raw BG data' : { cs: 'Když je povoleno, malé tečky budou zobrazeny pro RAW data' @@ -6114,6 +6361,7 @@ function init() { ,tr: 'Etkinleştirildiğinde, ham KŞ verileri için küçük beyaz noktalar görüntülenecektir.' ,zh_cn: '启用后将使用小白点标注原始血糖数据' ,zh_tw: '啟用後將使用小白點標註原始血糖數據' + ,hu: 'Bekapcsolasnál kis fehért pontok fogják jelezni a nyers BG adatokat' } ,'Custom Title' : { cs: 'Vlastní název stránky' @@ -6140,6 +6388,7 @@ function init() { ,tr: 'Özel Başlık' ,zh_cn: '自定义标题' ,zh_tw: '自定義標題' + ,hu: 'Saját Cím' } ,'Theme' : { cs: 'Téma' @@ -6166,6 +6415,7 @@ function init() { ,tr: 'Tema' ,zh_cn: '主题' ,zh_tw: '主題' + ,hu: 'Téma' } ,'Default' : { cs: 'Výchozí' @@ -6192,6 +6442,7 @@ function init() { ,tr: 'Varsayılan' ,zh_cn: '默认' ,zh_tw: '默認' + ,hu: 'Alap' } ,'Colors' : { cs: 'Barevné' @@ -6218,6 +6469,7 @@ function init() { ,tr: 'Renkler' ,zh_cn: '彩色' ,zh_tw: '彩色' + ,hu: 'Színek' } ,'Colorblind-friendly colors' : { cs: 'Pro barvoslepé' @@ -6244,6 +6496,7 @@ function init() { ,pl: 'Kolory dla niedowidzących' ,tr: 'Renk körü dostu görünüm' ,ru: 'Цветовая гамма для людей с нарушениями восприятия цвета' + ,hu: 'Beállítás színvakok számára' } ,'Reset, and use defaults' : { cs: 'Vymaž a nastav výchozí hodnoty' @@ -6270,6 +6523,7 @@ function init() { ,tr: 'Sıfırla ve varsayılanları kullan' ,zh_cn: '使用默认值重置' ,zh_tw: '使用默認值重置' + ,hu: 'Visszaállítás a kiinduló állapotba' } ,'Calibrations' : { cs: 'Kalibrace' @@ -6295,6 +6549,7 @@ function init() { ,ko: '보정' ,tr: 'Kalibrasyon' ,zh_cn: '校准' + ,hu: 'Kalibráció' } ,'Alarm Test / Smartphone Enable' : { cs: 'Test alarmu' @@ -6321,6 +6576,7 @@ function init() { ,tr: 'Alarm Testi / Akıllı Telefon için Etkin' ,zh_cn: '报警测试/智能手机启用' ,zh_tw: '報警測試/智能手機啟用' + ,hu: 'Figyelmeztetés teszt / Mobiltelefon aktiválása' } ,'Bolus Wizard' : { cs: 'Bolusový kalkulátor' @@ -6347,6 +6603,7 @@ function init() { ,tr: 'Bolus Hesaplayıcısı' ,zh_cn: '大剂量向导' ,zh_tw: '大劑量嚮導' + ,hu: 'Bólus Varázsló' } ,'in the future' : { cs: 'v budoucnosti' @@ -6373,6 +6630,7 @@ function init() { ,tr: 'gelecekte' ,zh_cn: '在未来' ,zh_tw: '在未來' + ,hu: 'a jövőben' } ,'time ago' : { cs: 'min zpět' @@ -6399,6 +6657,7 @@ function init() { ,tr: 'süre önce' //yakın zamanda ,zh_cn: '在过去' ,zh_tw: '在過去' + ,hu: 'idő elött' } ,'hr ago' : { cs: 'hod zpět' @@ -6425,6 +6684,7 @@ function init() { ,tr: 'saat önce' ,zh_cn: '小时前' ,zh_tw: '小時前' + ,hu: 'óra elött' } ,'hrs ago' : { cs: 'hod zpět' @@ -6451,6 +6711,7 @@ function init() { ,tr: 'saat önce' ,zh_cn: '小时前' ,zh_tw: '小時前' + ,hu: 'órája' } ,'min ago' : { cs: 'min zpět' @@ -6477,6 +6738,7 @@ function init() { ,tr: 'dk. önce' ,zh_cn: '分钟前' ,zh_tw: '分鐘前' + ,hu: 'perce' } ,'mins ago' : { cs: 'min zpět' @@ -6503,6 +6765,7 @@ function init() { ,tr: 'dakika önce' ,zh_cn: '分钟前' ,zh_tw: '分鐘前' + ,hu: 'perce' } ,'day ago' : { cs: 'den zpět' @@ -6529,6 +6792,7 @@ function init() { ,tr: 'gün önce' ,zh_cn: '天前' ,zh_tw: '天前' + ,hu: 'napja' } ,'days ago' : { cs: 'dnů zpět' @@ -6555,6 +6819,7 @@ function init() { ,tr: 'günler önce' ,zh_cn: '天前' ,zh_tw: '天前' + ,hu: 'napja' } ,'long ago' : { cs: 'dlouho zpět' @@ -6581,6 +6846,7 @@ function init() { ,tr: 'uzun zaman önce' ,zh_cn: '很长时间前' ,zh_tw: '很長時間前' + ,hu: 'nagyon régen' } ,'Clean' : { cs: 'Čistý' @@ -6607,6 +6873,7 @@ function init() { ,tr: 'Temiz' ,zh_cn: '无' ,zh_tw: '無' + ,hu: 'Tiszta' } ,'Light' : { cs: 'Lehký' @@ -6633,6 +6900,7 @@ function init() { ,tr: 'Kolay' ,zh_cn: '轻度' ,zh_tw: '輕度' + ,hu: 'Könnyű' } ,'Medium' : { cs: 'Střední' @@ -6659,6 +6927,7 @@ function init() { ,tr: 'Orta' ,zh_cn: '中度' ,zh_tw: '中度' + ,hu: 'Közepes' } ,'Heavy' : { cs: 'Velký' @@ -6685,6 +6954,7 @@ function init() { ,zh_cn: '重度' ,zh_tw: '嚴重' ,he: 'כבד' + ,hu: 'Nehéz' } ,'Treatment type' : { cs: 'Typ ošetření' @@ -6710,7 +6980,8 @@ function init() { ,tr: 'Tedavi tipi' ,zh_cn: '操作类型' ,he: 'סוג הטיפול' - } + ,hu: 'Kezelés típusa' + } ,'Raw BG' : { cs: 'Glykémie z RAW dat' ,de: 'Roh-BG' @@ -6733,7 +7004,8 @@ function init() { ,ko: 'Raw 혈당' ,tr: 'Ham KŞ' ,zh_cn: '原始血糖' - } + ,hu: 'Nyers BG' + } ,'Device' : { cs: 'Zařízení' ,de: 'Gerät' @@ -6758,7 +7030,8 @@ function init() { ,tr: 'Cihaz' ,zh_cn: '设备' ,he: 'התקן' - } + ,hu: 'Berendezés' + } ,'Noise' : { cs: 'Šum' ,he: 'רַעַשׁ' @@ -6783,6 +7056,7 @@ function init() { ,ko: '노이즈' ,tr: 'parazit' // gürültü ,zh_cn: '噪声' + ,hu: 'Zavar' } ,'Calibration' : { cs: 'Kalibrace' @@ -6808,6 +7082,7 @@ function init() { ,ko: '보정' ,tr: 'Kalibrasyon' ,zh_cn: '校准' + ,hu: 'Kalibráció' } ,'Show Plugins' : { cs: 'Zobrazuj pluginy' @@ -6832,8 +7107,8 @@ function init() { ,nl: 'Laat Plug-Ins zien' ,ko: '플러그인 보기' ,tr: 'Eklentileri Göster' - ,zh_cn: '显示插件' - ,zh_tw: '顯示插件' + ,zh_cn: '校准' + ,hu: 'Mutasd a kiegészítőket' } ,'About' : { cs: 'O aplikaci' @@ -6860,6 +7135,7 @@ function init() { ,tr: 'Hakkında' ,zh_cn: '关于' ,zh_tw: '關於' + ,hu: 'Az aplikációról' } ,'Value in' : { cs: 'Hodnota v' @@ -6885,6 +7161,7 @@ function init() { ,ko: '값' ,tr: 'Değer cinsinden' ,zh_cn: '数值' + ,hu: 'Érték' } ,'Carb Time' : { cs: 'Čas jídla' @@ -6909,7 +7186,8 @@ function init() { ,nl: 'Koolhydraten tijd' ,ko: '탄수화물 시간' ,tr: 'Karbonhidratların alım zamanı' - ,zh_cn: '碳水时间' + ,zh_cn: '数值' + ,hu: 'Étkezés ideje' } ,'Language' : { cs: 'Jazyk' @@ -6936,6 +7214,7 @@ function init() { ,tr: 'Dil' ,zh_cn: '语言' ,zh_tw: '語言' + ,hu: 'Nyelv' } ,'Add new' : { cs: 'Přidat nový' @@ -6961,6 +7240,7 @@ function init() { ,ja: '新たに加える' ,tr: 'Yeni ekle' ,zh_cn: '新增' + ,hu: 'Új hozzáadása' } ,'g' : { // grams shortcut cs: 'g' @@ -6986,6 +7266,7 @@ function init() { ,tr: 'g' ,zh_cn: '克' ,zh_tw: '克' + ,hu: 'g' } ,'ml' : { // milliliters shortcut cs: 'ml' @@ -7010,7 +7291,8 @@ function init() { ,ja: 'ml' ,tr: 'ml' ,zh_cn: '毫升' - ,zh_tw: '毫升' + ,zh_tw: '克' + ,hu: 'ml' } ,'pcs' : { // pieces shortcut cs: 'ks' @@ -7036,6 +7318,7 @@ function init() { ,tr: 'parça' ,zh_cn: '件' ,zh_tw: '件' + ,hu: 'db' } ,'Drag&drop food here' : { cs: 'Sem táhni & pusť jídlo' @@ -7060,6 +7343,7 @@ function init() { ,tr: 'Yiyecekleri buraya sürükle bırak' ,zh_cn: '拖放食物到这' ,nl: 'Maaltijd naar hier verplaatsen' + ,hu: 'Húzd ide és ereszd el az ételt' } ,'Care Portal' : { cs: 'Portál ošetření' @@ -7084,6 +7368,7 @@ function init() { ,tr: 'Care Portal' ,zh_cn: '服务面板' ,zh_tw: '服務面板' + ,hu: 'Care portál' } ,'Medium/Unknown' : { // GI of food cs: 'Střední/Neznámá' @@ -7108,6 +7393,7 @@ function init() { ,it: 'Media/Sconosciuto' ,tr: 'Orta/Bilinmeyen' ,zh_cn: '中等/不知道' + ,hu: 'Átlagos/Ismeretlen' } ,'IN THE FUTURE' : { cs: 'V BUDOUCNOSTI' @@ -7132,6 +7418,7 @@ function init() { ,it: 'NEL FUTURO' ,tr: 'GELECEKTE' ,zh_cn: '在未来' + ,hu: 'A JÖVŐBEN' } ,'Update' : { // Update button cs: 'Aktualizovat' @@ -7157,6 +7444,7 @@ function init() { ,tr: 'Güncelleştirme' ,zh_cn: '更新认证状态' ,zh_tw: '更新認證狀態' + ,hu: 'Frissítés' } ,'Order' : { cs: 'Pořadí' @@ -7181,6 +7469,7 @@ function init() { ,ko: '순서' ,tr: 'Sıra' ,zh_cn: '排序' + ,hu: 'Sorrend' } ,'oldest on top' : { cs: 'nejstarší nahoře' @@ -7205,7 +7494,8 @@ function init() { ,ko: '오래된 것 부터' ,tr: 'en eski üste' ,zh_cn: '按时间升序排列' - } + ,hu: 'legöregebb a telejére' + } ,'newest on top' : { cs: 'nejnovější nahoře' ,he: 'החדש ביותר למעלה' @@ -7229,6 +7519,7 @@ function init() { ,ko: '새로운 것 부터' ,tr: 'en yeni üste' ,zh_cn: '按时间降序排列' + ,hu: 'legújabb a tetejére' } ,'All sensor events' : { cs: 'Všechny události sensoru' @@ -7254,6 +7545,7 @@ function init() { ,ko: '모든 센서 이벤트' ,tr: 'Tüm sensör olayları' ,zh_cn: '所有探头事件' + ,hu: 'Az összes szenzor esemény' } ,'Remove future items from mongo database' : { cs: 'Odebrání položek v budoucnosti z Mongo databáze' @@ -7279,6 +7571,7 @@ function init() { ,tr: 'Gelecekteki öğeleri mongo veritabanından kaldır' ,zh_cn: '从数据库中清除所有未来条目' ,zh_tw: '從數據庫中清除所有未來條目' + ,hu: 'Töröld az összes jövőben lévő adatot az adatbázisból' } ,'Find and remove treatments in the future' : { cs: 'Najít a odstranit záznamy ošetření v budoucnosti' @@ -7304,6 +7597,7 @@ function init() { ,tr: 'Gelecekte tedavileri bulun ve kaldır' ,zh_cn: '查找并清除所有未来的操作' ,zh_tw: '查找並清除所有未來的操作' + ,hu: 'Töröld az összes kezelést a jövőben az adatbázisból' } ,'This task find and remove treatments in the future.' : { cs: 'Tento úkol najde a odstraní ošetření v budoucnosti.' @@ -7329,6 +7623,7 @@ function init() { ,tr: 'Bu görev gelecekte tedavileri bul ve kaldır.' ,zh_cn: '此功能查找并清除所有未来的操作。' ,zh_tw: '此功能查找並清除所有未來的操作。' + ,hu: 'Ez a feladat megkeresi és eltávolítja az összes jövőben lévő kezelést' } ,'Remove treatments in the future' : { cs: 'Odstraň ošetření v budoucnosti' @@ -7354,6 +7649,7 @@ function init() { ,tr: 'Gelecekte tedavileri kaldır' ,zh_cn: '清除未来操作' ,zh_tw: '清除未來操作' + ,hu: 'Jövőbeli kerelések eltávolítésa' } ,'Find and remove entries in the future' : { cs: 'Najít a odstranit CGM data v budoucnosti' @@ -7379,6 +7675,7 @@ function init() { ,tr: 'Gelecekteki girdileri bul ve kaldır' ,zh_cn: '查找并清除所有的未来的记录' ,zh_tw: '查找並清除所有的未來的記錄' + ,hu: 'Jövőbeli bejegyzések eltávolítása' } ,'This task find and remove CGM data in the future created by uploader with wrong date/time.' : { cs: 'Tento úkol najde a odstraní CGM data v budoucnosti vzniklé špatně nastaveným datem v uploaderu.' @@ -7404,6 +7701,7 @@ function init() { ,tr: 'Yükleyicinin oluşturduğu gelecekteki CGM verilerinin yanlış tarih/saat olanlarını bul ve kaldır.' ,zh_cn: '此功能查找并清除所有上传时日期时间错误导致生成在未来时间的CGM数据。' ,zh_tw: '此功能查找並清除所有上傳時日期時間錯誤導致生成在未來時間的CGM數據。' + ,hu: 'Ez a feladat megkeresi és eltávolítja az összes CGM adatot amit a feltöltő rossz idővel-dátummal töltött fel' } ,'Remove entries in the future' : { cs: 'Odstraň CGM data v budoucnosti' @@ -7429,6 +7727,7 @@ function init() { ,tr: 'Gelecekteki girdileri kaldır' ,zh_cn: '清除未来记录' ,zh_tw: '清除未來記錄' + ,hu: 'Jövőbeli bejegyzések törlése' } ,'Loading database ...' : { cs: 'Nahrávám databázi ...' @@ -7454,6 +7753,7 @@ function init() { ,tr: 'Veritabanı yükleniyor ...' ,zh_cn: '载入数据库...' ,zh_tw: '載入數據庫...' + ,hu: 'Adatbázis betöltése...' } ,'Database contains %1 future records' : { cs: 'Databáze obsahuje %1 záznamů v budoucnosti' @@ -7479,6 +7779,7 @@ function init() { ,tr: 'Veritabanı %1 gelecekteki girdileri içeriyor' ,zh_cn: '数据库包含%1条未来记录' ,zh_tw: '數據庫包含%1條未來記錄' + ,hu: 'Az adatbázis %1 jövöbeli adatot tartalmaz' } ,'Remove %1 selected records?' : { cs: 'Odstranit %1 vybraných záznamů' @@ -7504,6 +7805,7 @@ function init() { ,tr: 'Seçilen %1 kayıtlar kaldırılsın? ' ,zh_cn: '清除%1条选择的记录?' ,zh_tw: '清除%1條選擇的記錄?' + ,hu: 'Kitöröljük a %1 kiválasztott adatot?' } ,'Error loading database' : { cs: 'Chyba při nahrávání databáze' @@ -7529,6 +7831,7 @@ function init() { ,tr: 'Veritabanını yüklerken hata oluştu' ,zh_cn: '载入数据库错误' ,zh_tw: '載入數據庫錯誤' + ,hu: 'Hiba az adatbázis betöltése közben' } ,'Record %1 removed ...' : { cs: 'Záznam %1 odstraněn ...' @@ -7554,6 +7857,7 @@ function init() { ,tr: '%1 kaydı silindi ...' ,zh_cn: '%1条记录已清除' ,zh_tw: '%1條記錄已清除' + ,hu: 'A %1 bejegyzés törölve...' } ,'Error removing record %1' : { cs: 'Chyba při odstaňování záznamu %1' @@ -7579,6 +7883,7 @@ function init() { ,tr: '%1 kayıt kaldırılırken hata oluştu' ,zh_cn: '%1条记录清除出错' ,zh_tw: '%1條記錄清除出錯' + ,hu: 'Hiba lépett fel a %1 bejegyzés törlése közben' } ,'Deleting records ...' : { cs: 'Odstraňování záznamů ...' @@ -7604,12 +7909,14 @@ function init() { ,tr: 'Kayıtlar siliniyor ...' ,zh_cn: '正在删除记录...' ,zh_tw: '正在刪除記錄...' + ,hu: 'Bejegyzések törlése...' } ,'%1 records deleted' : { hr: 'obrisano %1 zapisa' ,de: '%1 Einträge gelöscht' , pl: '%1 rekordów zostało usuniętych' ,ru: '% записей удалено' + ,hu: '%1 bejegyzés törölve' } ,'Clean Mongo status database' : { cs: 'Vyčištění Mongo databáze statusů' @@ -7634,6 +7941,7 @@ function init() { ,ko: 'Mongo 상태 데이터베이스를 지우세요.' ,tr: 'Mongo durum veritabanını temizle' ,zh_cn: '清除状态数据库' + ,hu: 'Mongo állapot (status) adatbázis tisztítása' } ,'Delete all documents from devicestatus collection' : { cs: 'Odstranění všech záznamů z kolekce devicestatus' @@ -7658,6 +7966,7 @@ function init() { ,tr: 'Devicestatus koleksiyonundan tüm dokümanları sil' ,zh_cn: '从设备状态采集删除所有文档' ,nl: 'Verwijder alle documenten uit "devicestatus" database' + ,hu: 'Az összes "devicestatus" dokumentum törlése' } ,'This task removes all documents from devicestatus collection. Useful when uploader battery status is not properly updated.' : { cs: 'Tento úkol odstraní všechny dokumenty z kolekce devicestatus. Je to vhodné udělat, pokud se ukazatel stavu baterie neobnovuje správně.' @@ -7681,6 +7990,7 @@ function init() { ,tr: 'Bu görev tüm durumları Devicestatus koleksiyonundan kaldırır. Yükleyici pil durumu güncellenmiyorsa kullanışlıdır.' ,zh_cn: '此功能从设备状态采集中删除所有文档。适用于上传设备电量信息不能正常同步时使用。' ,nl: 'Dit commando verwijdert alle documenten uit "devicestatus" database. Handig wanneer de batterij status niet correct wordt geupload.' + ,hu: 'Ez a feladat kitörli az összes "devicestatus" dokumentumot. Hasznos ha a feltöltő elem állapota nem jelenik meg helyesen.' } ,'Delete all documents' : { cs: 'Odstranit všechny dokumenty' @@ -7705,6 +8015,7 @@ function init() { ,ko: '모든 문서들을 지우세요' ,tr: 'Tüm Belgeleri sil' ,zh_cn: '删除所有文档' + ,hu: 'Az összes dokumentum törlése' } ,'Delete all documents from devicestatus collection?' : { cs: 'Odstranit všechny dokumenty z kolekce devicestatus?' @@ -7729,6 +8040,7 @@ function init() { ,tr: 'Tüm Devicestatus koleksiyon belgeleri silinsin mi?' ,zh_cn: '从设备状态采集删除所有文档?' ,nl: 'Wil je alle data van "devicestatus" database verwijderen?' + ,hu: 'Az összes dokumentum törlése a "devicestatus" gyűjteményből?' } ,'Database contains %1 records' : { cs: 'Databáze obsahuje %1 záznamů' @@ -7753,6 +8065,7 @@ function init() { ,ko: '데이터베이스는 %1 기록을 포함합니다.' ,tr: 'Veritabanı %1 kayıt içeriyor' ,zh_cn: '数据库包含%1条记录' + ,hu: 'Az adatbázis %1 bejegyzést tartalmaz' } ,'All records removed ...' : { cs: 'Všechny záznamy odstraněny ...' @@ -7777,60 +8090,70 @@ function init() { ,ko: '모든 기록들이 지워졌습니다.' ,tr: 'Tüm kayıtlar kaldırıldı ...' ,zh_cn: '所有记录已经被清除' + ,hu: 'Az összes bejegyzés törölve...' } ,'Delete all documents from devicestatus collection older than 30 days' : { hr: 'Obriši sve statuse starije od 30 dana' ,ru: 'Удалить все записи коллекции devicestatus старше 30 дней' ,de: 'Alle Dokumente der Gerätestatus-Sammlung löschen, die älter als 30 Tage sind' , pl: 'Usuń wszystkie dokumenty z kolekcji devicestatus starsze niż 30 dni' + , hu: 'Az összes "devicestatus" dokumentum törlése ami 30 napnál öregebb' } ,'Number of Days to Keep:' : { hr: 'Broj dana za sačuvati:' ,ru: 'Оставить дней' ,de: 'Daten löschen, die älter sind (in Tagen) als:' , pl: 'Ilość dni do zachowania:' + , hu: 'Mentés ennyi napra:' } ,'This task removes all documents from devicestatus collection that are older than 30 days. Useful when uploader battery status is not properly updated.' : { hr: 'Ovo uklanja sve statuse starije od 30 dana. Korisno kada se status baterije uploadera ne osvježava ispravno.' , pl: 'To narzędzie usuwa wszystkie dokumenty z kolekcji devicestatus starsze niż 30 dni. Przydatne, gdy status baterii uploadera nie jest aktualizowany.' ,ru: 'Это удалит все документы коллекции devicestatus которым более 30 дней. Полезно, когда статус батареи не обновляется или обновляется неверно.' ,de: 'Diese Aufgabe entfernt alle Dokumente aus der Gerätestatus-Sammlung, die älter sind als 30 Tage. Nützlich wenn der Uploader-Batteriestatus sich nicht aktualisiert.' + ,hu: 'Ez a feladat törli az összes "devicestatus" dokumentumot a gyűjteményből ami 30 napnál öregebb. Hasznos ha a feltöltő elem állapota nem jelenik meg rendesen. ' } ,'Delete old documents from devicestatus collection?' : { hr: 'Obriši stare statuse' ,de: 'Alte Dokumente aus der Gerätestatus-Sammlung entfernen?' , pl: 'Czy na pewno chcesz usunąć stare dokumenty z kolekcji devicestatus?' ,ru: 'Удалить старыые документы коллекции devicestatus' + ,hu: 'Kitorli az öreg dokumentumokat a "devicestatus" gyűjteményből?' } ,'Clean Mongo entries (glucose entries) database' : { hr: 'Obriši GUK zapise iz baze' ,de: 'Mongo-Einträge (Glukose-Einträge) Datenbank bereinigen' , pl: 'Wyczyść bazę wpisów (wpisy glukozy) Mongo' ,ru: 'Очистить записи данных в базе Mongo' + ,hu: 'Mongo bejegyzés adatbázis tisztítása' } ,'Delete all documents from entries collection older than 180 days' : { hr: 'Obriši sve zapise starije od 180 dana' ,de: 'Alle Dokumente aus der Einträge-Sammlung löschen, die älter sind als 180 Tage' , pl: 'Usuń wszystkie dokumenty z kolekcji wpisów starsze niż 180 dni' ,ru: 'Удалить все документы коллекции entries старше 180 дней ' + ,hu: 'Az összes bejegyzés gyűjtemény törlése ami 180 napnál öregebb' } ,'This task removes all documents from entries collection that are older than 180 days. Useful when uploader battery status is not properly updated.' : { hr: 'Ovo briše sve zapise starije od 180 dana. Korisno kada se status baterije uploadera ne osvježava.' ,de: 'Diese Aufgabe entfernt alle Dokumente aus der Einträge-Sammlung, die älter sind als 180 Tage. Nützlich wenn der Uploader-Batteriestatus sich nicht aktualisiert.' , pl: 'To narzędzie usuwa wszystkie dokumenty z kolekcji wpisów starsze niż 180 dni. Przydatne, gdy status baterii uploadera nie jest aktualizowany.' ,ru: 'Это удалит все документы коллекции entries старше 180 дней. Полезно, когда статус батареи загрузчика должным образом не обновляется' + ,hu: 'A feladat kitörli az összes bejegyzésekből álló dokumentumot ami 180 napnál öregebb. Hasznos ha a feltöltő elem állapota nem jelenik meg helyesen.' } ,'Delete old documents' : { hr: 'Obriši stare zapise' ,de: 'Alte Dokumente löschen' , pl: 'Usuń stare dokumenty' ,ru: 'Удалить старые документы' + ,hu: 'Öreg dokumentumok törlése' } ,'Delete old documents from entries collection?' : { hr: 'Obriši stare zapise?' ,de: 'Alte Dokumente aus der Einträge-Sammlung entfernen?' , pl: 'Czy na pewno chcesz usunąć stare dokumenty z kolekcji wpisów?' ,ru: 'Удалить старые документы коллекции entries?' + ,hu: 'Az öreg dokumentumok törlése a bejegyzések gyűjteményéből?' } ,'%1 is not a valid number' : { hr: '%1 nije valjan broj' @@ -7838,36 +8161,42 @@ function init() { ,he: 'זה לא מיספר %1' , pl: '%1 nie jest poprawną liczbą' ,ru: '% не является допустимым значением' + ,hu: 'A %1 nem érvényes szám' } ,'%1 is not a valid number - must be more than 2' : { hr: '%1 nije valjan broj - mora biti veći od 2' ,de: '%1 ist keine gültige Zahl - Eingabe muss größer als 2 sein' , pl: '%1 nie jest poprawną liczbą - musi być większe od 2' ,ru: '% не является допустимым значением - должно быть больше 2' + ,hu: 'A %1 nem érvényes szám - nagyobb számnak kell lennie mint a 2' } ,'Clean Mongo treatments database' : { hr: 'Obriši tretmane iz baze' ,de: 'Mongo-Behandlungsdatenbank bereinigen' , pl: 'Wyczyść bazę leczenia Mongo' ,ru: 'Очистить базу лечения Mongo' + ,hu: 'Mondo kezelési datbázisának törlése' } ,'Delete all documents from treatments collection older than 180 days' : { hr: 'Obriši tretmane starije od 180 dana iz baze' ,de: 'Alle Dokumente aus der Behandlungs-Sammlung löschen, die älter sind als 180 Tage' , pl: 'Usuń wszystkie dokumenty z kolekcji leczenia starsze niż 180 dni' ,ru: 'Удалить все документы коллекции treatments старше 180 дней' + ,hu: 'Töröld az összes 180 napnál öregebb kezelési dokumentumot' } ,'This task removes all documents from treatments collection that are older than 180 days. Useful when uploader battery status is not properly updated.' : { hr: 'Ovo briše sve tretmane starije od 180 dana iz baze. Korisno kada se status baterije uploadera ne osvježava.' ,de: 'Diese Aufgabe entfernt alle Dokumente aus der Behandlungs-Sammlung, die älter sind als 180 Tage. Nützlich wenn der Uploader-Batteriestatus sich nicht aktualisiert.' , pl: 'To narzędzie usuwa wszystkie dokumenty z kolekcji leczenia starsze niż 180 dni. Przydatne, gdy status baterii uploadera nie jest aktualizowany.' ,ru: 'Это удалит все документы коллекции treatments старше 180 дней. Полезно, когда статус батареи загрузчика не обновляется должным образом' + ,hu: 'A feladat eltávolítja az összes kezelési dokumentumot ami öregebb 180 napnál. Hasznos ha a feltöltő elem állapota nem jelenik meg helyesen.' } ,'Delete old documents from treatments collection?' : { hr: 'Obriši stare tretmane?' ,ru: 'Удалить старые документы из коллекции treatments?' ,de: 'Alte Dokumente aus der Behandlungs-Sammlung entfernen?' , pl: 'Czy na pewno chcesz usunąć stare dokumenty z kolekcji leczenia?' + , hu: 'Törölni az összes doumentumot a kezelési gyűjteményből?' } ,'Admin Tools' : { cs: 'Nástroje pro správu' @@ -7894,6 +8223,7 @@ function init() { ,tr: 'Yönetici araçları' ,zh_cn: '管理工具' ,zh_tw: '管理工具' + ,hu: 'Adminisztrációs eszközök' } ,'Nightscout reporting' : { cs: 'Nightscout - Výkazy' @@ -7918,6 +8248,7 @@ function init() { ,ko: 'Nightscout 보고서' ,tr: 'NightScout raporları' ,zh_cn: 'Nightscout报表生成器' + ,hu: 'Nightscout jelentések' } ,'Cancel' : { cs: 'Zrušit' @@ -7943,6 +8274,7 @@ function init() { ,ko: '취소' ,tr: 'İptal' ,zh_cn: '取消' + ,hu: 'Vissza' } ,'Edit treatment' : { cs: 'Upravit ošetření' @@ -7967,6 +8299,7 @@ function init() { ,ko: 'Treatments 편집' ,tr: 'Tedaviyi düzenle' ,zh_cn: '编辑操作' + ,hu: 'Kezelés szerkesztése' } ,'Duration' : { cs: 'Doba trvání' @@ -7991,6 +8324,7 @@ function init() { ,ko: '기간' ,tr: 'süre' ,zh_cn: '持续' + ,hu: 'Behelyezés óta eltelt idő' } ,'Duration in minutes' : { cs: 'Doba trvání v minutách' @@ -8015,6 +8349,7 @@ function init() { ,ko: '분당 지속 기간' ,tr: 'Süre dakika cinsinden' ,zh_cn: '持续时间(分钟)' + ,hu: 'Idő percekben' } ,'Temp Basal' : { cs: 'Dočasný bazál' @@ -8038,6 +8373,7 @@ function init() { ,ko: '임시 basal' ,tr: 'Geçici Bazal Oranı' ,zh_cn: '临时基础率' + ,hu: 'Átmeneti bazál' } ,'Temp Basal Start' : { cs: 'Dočasný bazál začátek' @@ -8061,6 +8397,7 @@ function init() { ,ko: '임시 basal 시작' ,tr: 'Geçici Bazal Oranını Başlanğıcı' ,zh_cn: '临时基础率开始' + ,hu: 'Átmeneti bazál Kezdete' } ,'Temp Basal End' : { cs: 'Dočasný bazál konec' @@ -8084,6 +8421,7 @@ function init() { ,ko: '임시 basal 종료' ,tr: 'Geçici bazal oranını Bitişi' ,zh_cn: '临时基础率结束' + ,hu: 'Átmeneti bazál Vége' } ,'Percent' : { // value in % for temp basal cs: 'Procenta' @@ -8108,6 +8446,7 @@ function init() { ,ko: '퍼센트' ,tr: 'Yüzde' ,zh_cn: '百分比' + ,hu: 'Százalék' } ,'Basal change in %' : { cs: 'Změna bazálu v %' @@ -8131,6 +8470,7 @@ function init() { ,ko: '% 이내의 basal 변경' ,tr: 'Bazal değişimi % cinsinden' ,zh_cn: '基础率变化百分比' + ,hu: 'Bazál változása %' } ,'Basal value' : { // absolute value for temp basal cs: 'Hodnota bazálu' @@ -8154,6 +8494,7 @@ function init() { ,ko: 'Basal' ,tr: 'Bazal değeri' ,zh_cn: '基础率值' + ,hu: 'Bazál értéke' } ,'Absolute basal value' : { cs: 'Hodnota bazálu' @@ -8177,6 +8518,7 @@ function init() { ,ko: '절대적인 basal' ,tr: 'Mutlak bazal değeri' ,zh_cn: '绝对基础率值' + ,hu: 'Abszolút bazál érték' } ,'Announcement' : { cs: 'Oznámení' @@ -8201,6 +8543,7 @@ function init() { ,ko: '공지' ,tr: 'Duyuru' ,zh_cn: '通告' + ,hu: 'Közlemény' } ,'Loading temp basal data' : { cs: 'Nahrávám dočasné bazály' @@ -8224,6 +8567,7 @@ function init() { ,ko: '임시 basal 로딩' ,tr: 'Geçici bazal verileri yükleniyor' ,zh_cn: '载入临时基础率数据' + ,hu: 'Az étmeneti bazál adatainak betöltése' } ,'Save current record before changing to new?' : { cs: 'Uložit současný záznam před změnou na nový?' @@ -8248,6 +8592,7 @@ function init() { ,it: 'Salvare i dati correnti prima di cambiarli?' ,tr: 'Yenisine geçmeden önce mevcut girişleri kaydet?' ,zh_cn: '在修改至新值前保存当前记录?' + ,hu: 'Elmentsem az aktuális adatokat mielőtt újra váltunk?' } ,'Profile Switch' : { cs: 'Přepnutí profilu' @@ -8272,6 +8617,7 @@ function init() { ,it: 'Cambio profilo' ,tr: 'Profil Değiştir' ,zh_cn: '切换配置文件' + ,hu: 'Profil csere' } ,'Profile' : { cs: 'Profil' @@ -8296,6 +8642,7 @@ function init() { ,ko: '프로파일' ,tr: 'Profil' ,zh_cn: '配置文件' + ,hu: 'Profil' } ,'General profile settings' : { cs: 'Obecná nastavení profilu' @@ -8320,6 +8667,7 @@ function init() { ,it: 'Impostazioni generali profilo' ,tr: 'Genel profil ayarları' ,zh_cn: '通用配置文件设置' + ,hu: 'Általános profil beállítások' } ,'Title' : { cs: 'Název' @@ -8344,6 +8692,7 @@ function init() { ,it: 'Titolo' ,tr: 'Başlık' ,zh_cn: '标题' + ,hu: 'Elnevezés' } ,'Database records' : { cs: 'Záznamy v databázi' @@ -8368,6 +8717,7 @@ function init() { ,tr: 'Veritabanı kayıtları' ,zh_cn: '数据库记录' ,nl: 'Database gegevens' + ,hu: 'Adatbázis bejegyzések' } ,'Add new record' : { cs: 'Přidat nový záznam' @@ -8393,6 +8743,7 @@ function init() { ,ja: '新しい記録を加える' ,tr: 'Yeni kayıt ekle' ,zh_cn: '新增记录' + ,hu: 'Új bejegyzés hozzáadása' } ,'Remove this record' : { cs: 'Vymazat tento záznam' @@ -8418,6 +8769,7 @@ function init() { ,ja: 'この記録を除く' ,tr: 'Bu kaydı kaldır' ,zh_cn: '删除记录' + ,hu: 'Bejegyzés törlése' } ,'Clone this record to new' : { cs: 'Zkopíruj tento záznam do nového' @@ -8442,6 +8794,7 @@ function init() { ,it: 'Clona questo record in uno nuovo' ,tr: 'Bu kaydı yeniden kopyala' ,zh_cn: '复制记录' + ,hu: 'A kiválasztott bejegyzés másolása' } ,'Record valid from' : { cs: 'Záznam platný od' @@ -8466,6 +8819,7 @@ function init() { ,it: 'Record valido da' ,tr: 'Kayıt itibaren geçerli' ,zh_cn: '有效记录,从' + ,hu: 'Bejegyzés érvényessége' } ,'Stored profiles' : { cs: 'Uložené profily' @@ -8490,6 +8844,7 @@ function init() { ,it: 'Profili salvati' ,tr: 'Kaydedilmiş profiller' //Kayıtlı profiller,Saklanan profiller ,zh_cn: '配置文件已存储' + ,hu: 'Tárolt profilok' } ,'Timezone' : { cs: 'Časová zóna' @@ -8514,6 +8869,7 @@ function init() { ,it: 'Fuso orario' ,tr: 'Saat dilimi' ,zh_cn: '时区' + ,hu: 'Időzóna' } ,'Duration of Insulin Activity (DIA)' : { cs: 'Doba působnosti inzulínu (DIA)' @@ -8538,6 +8894,7 @@ function init() { ,it: 'Durata Attività Insulinica (DIA)' ,tr: 'İnsülin Etki Süresi (DIA)' ,zh_cn: '胰岛素作用时间(DIA)' + ,hu: 'Inzulin aktivitás időtartalma' } ,'Represents the typical duration over which insulin takes effect. Varies per patient and per insulin type. Typically 3-4 hours for most pumped insulin and most patients. Sometimes also called insulin lifetime.' : { cs: 'Představuje typickou dobu, po kterou inzulín působí. Bývá různá podle pacienta a inzulínu. Typicky 3-4 hodiny pro pacienty s pumpou.' @@ -8562,6 +8919,7 @@ function init() { ,it: 'Rappresenta la durata tipica nel quale l\'insulina ha effetto. Varia in base al paziente ed al tipo d\'insulina. Tipicamente 3-4 ore per la maggior parte dei microinfusori e dei pazienti. Chiamata anche durata d\'azione insulinica.' ,tr: 'İnsülinin etki ettiği tipik süreye karşılık gelir. Hastaya ve insülin tipine göre değişir. Çoğu pompa insülini ve çoğu hasta için genellikle 3-4 saattir. Bazen de insülin etki süresi de denir.' ,zh_cn: '体现典型的胰岛素活性持续时间。 通过百分比和胰岛素类型体现。对于大多数胰岛素和患者来说是3至4个小时。也称为胰岛素生命周期。' + ,hu: 'Kimutatja hogy általában meddig hat az inzulin. Változó különböző pácienseknél és inzulinoknál. Általában 3-4 óra között mozog. Néha inzulin élettartalomnak is nevezik.' } ,'Insulin to carb ratio (I:C)' : { cs: 'Inzulíno-sacharidový poměr (I:C).' @@ -8586,6 +8944,7 @@ function init() { ,it: 'Rapporto Insulina-Carboidrati (I:C)' ,tr: 'İnsülin/Karbonhidrat oranı (I:C)' ,zh_cn: '碳水化合物系数(ICR)' + ,hu: 'Inzulin-szénhidrát arány' } ,'Hours:' : { cs: 'Hodin:' @@ -8610,6 +8969,7 @@ function init() { ,it: 'Ore:' ,tr: 'Saat:' ,zh_cn: '小时:' + ,hu: 'Óra:' } ,'hours' : { cs: 'hodin' @@ -8634,6 +8994,7 @@ function init() { ,it: 'ore' ,tr: 'saat' ,zh_cn: '小时' + ,hu: 'óra' } ,'g/hour' : { cs: 'g/hod' @@ -8657,6 +9018,7 @@ function init() { ,it: 'g/ora' ,tr: 'g/saat' ,zh_cn: 'g/小时' + ,hu: 'g/óra' } ,'g carbs per U insulin. The ratio of how many grams of carbohydrates are offset by each U of insulin.' : { cs: 'gramy na jednotku inzulínu. Poměr, jaké množství sacharidů pokryje jednotku inzulínu.' @@ -8681,6 +9043,7 @@ function init() { ,tr: 'İnsülin ünite başına g karbonhidrat. İnsülin ünite başına kaç gram karbonhidrat tüketildiği oranıdır.' ,zh_cn: '克碳水每单位胰岛素。每单位胰岛素可以抵消的碳水化合物克值比例。' ,nl: 'G KH per Eh insuline. De verhouding tussen hoeveel grammen koohlhydraten er verwerkt kunnen worden per eenheid insuline.' + ,hu: 'g szénhidrát per egység inzulin. Az arány, hogy hány gramm szénhidrát fed le bizonyos egységnyi inzulint' } ,'Insulin Sensitivity Factor (ISF)' : { cs: 'Citlivost inzulínu (ISF)' @@ -8705,6 +9068,7 @@ function init() { ,it: 'Fattore di Sensibilità Insulinica (ISF)' ,tr: '(ISF) İnsülin Duyarlılık Faktörü' ,zh_cn: '胰岛素敏感系数(ISF)' + ,hu: 'Inzulin Érzékenységi Faktor (ISF)' } ,'mg/dL or mmol/L per U insulin. The ratio of how much BG changes with each U of corrective insulin.' : { cs: 'mg/dL nebo mmol/L na jednotku inzulínu. Poměr, jak se změní glykémie po podaní jednotky inzulínu' @@ -8729,6 +9093,7 @@ function init() { ,it: 'mg/dL o mmol/L per U insulina. Il rapporto di quanto la glicemia varia per ogni U di correzione insulinica.' ,tr: 'Ünite insülin başına mg/dL veya mmol/L. Her bir Ünite düzeltme insülin ile KŞ\'nin ne kadar değiştiğini gösteren orandır.' ,zh_cn: 'mg/dL或mmol/L每单位胰岛素。每单位输入胰岛素导致血糖变化的比例' + ,hu: 'mg/dL vagy mmol/L per inzulin egység. Az aránya annak hogy mennyire változik a cukorszint bizonyos egység inzulintól' } ,'Carbs activity / absorption rate' : { cs: 'Rychlost absorbce sacharidů' @@ -8753,8 +9118,9 @@ function init() { ,it: 'Attività carboidrati / Velocità di assorbimento' ,tr: 'Karbonhidrat aktivitesi / emilim oranı' ,zh_cn: '碳水化合物活性/吸收率' + ,hu: 'Szénhidrátok felszívódásának gyorsasága' } - ,'grams peUr unit time. Represents both the change in COB per unit of time, as well as the amount of carbs that should take effect over that time. Carb absorption / activity curves are less well understood than insulin activity, but can be approximated using an initial delay followed by a constant rate of absorption (g/hr).' : { + ,'grams per unit time. Represents both the change in COB per unit of time, as well as the amount of carbs that should take effect over that time. Carb absorption / activity curves are less well understood than insulin activity, but can be approximated using an initial delay followed by a constant rate of absorption (g/hr).' : { cs: 'gramy za jednotku času. Reprezentuje jak změnu COB za jednoku času, tak množství sacharidů, které se za tu dobu projevily. Křivka absorbce sacharidů je mnohem méně pochopitelná než IOB, ale může být aproximována počáteční pauzou následovanou konstantní hodnotou absorbce (g/hod).' ,he: 'גרם ליחידת זמן. מייצג הן את השינוי בפחמימות ליחידת זמן והן את כמות הפחמימות אשר אמורות להיכנס לתוקף במהלך אותה תקופה. ספיגת הפחמימות / פעילות הם פחות מובן מאשר פעילות האינסולין, אך ניתן להתקרב באמצעות עיכוב ראשוני ואחריו שיעור קבוע של קליטה (g / hr) ' ,el: 'Γραμμάρια ανά μονάδα χρόνου. Αναπαριστά τόσο την μεταβολή του COB στη μονάδα του χρόνου. Οι καμπύλες της απορρόφησης υδατανθράκων και της άσκησης δεν έχουν κατανοηθεί πλήρως από την επιστημονική κοινότητα, αλλά μπορούν να προσεγγιστούν βάζοντας μία αρχική καθυστέρηση ακολουθούμενη από έναν σταθερό ρυθμό απορρόφησης (g/hr).' @@ -8777,6 +9143,7 @@ function init() { ,tr: 'Ur birim zaman başına gram. Birim zamanda (COB) Aktif Krabonhidratdaki değişimin yanı sıra o zaman üzerinde etki etmesi gereken karbonhidrat miktarını ifade eder. Karbonhidrat emme/aktivite eğrileri, insülin aktivitesinden daha zor anlaşılmaktadır, ancak bir başlangıç gecikmesi ve ardından sabit bir emilim oranı (g/hr) kullanılarak yaklaşık olarak tahmin edilebilmektedir.' ,zh_cn: '克每单位时间。表示每单位时间COB(活性碳水化合物)的变化,以及在该时间应该生效的碳水化合物的量。碳水化合物活性/吸收曲线比胰岛素活性难理解,但可以使用初始延迟,接着恒定吸收速率(克/小时)来近似模拟。' ,nl: 'grammen per tijdseenheid. Geeft de wijzigingen in COB per tijdseenheid alsookde hoeveelheid KH dat impact zou moeten hebben over deze tijdspanne. KH absorbtie / activiteits curveszijn minder eenvoudig uitzetbaar, maar kunnen geschat worden door gebruik te maken van een startvertreging en daarna een constante curve van absorbtie (g/u).' + ,hu: 'gramm per idő egység. Kifejezi a COB változását es a szénhidrátok felszívódását bizonyos idő elteltével. A szénhidrát felszívódásának tengelye nehezebben értelmezhető mint az inzulin aktivitás (IOB), de hasonló lehet a kezdeti késedelemhez és a felszívódáshoz (g/óra). ' } ,'Basal rates [unit/hour]' : { cs: 'Bazály [U/hod].' @@ -8801,6 +9168,7 @@ function init() { ,it: 'Basale [unità/ora]' ,tr: 'Bazal oranı [ünite/saat]' ,zh_cn: '基础率 [U/小时]' + ,hu: 'Bazál [egység/óra]' } ,'Target BG range [mg/dL,mmol/L]' : { cs: 'Cílový rozsah glykémií [mg/dL,mmol/L]' @@ -8825,6 +9193,7 @@ function init() { ,it: 'Obiettivo d\'intervallo glicemico [mg/dL,mmol/L]' ,tr: 'Hedef KŞ aralığı [mg / dL, mmol / L]' ,zh_cn: '目标血糖范围 [mg/dL,mmol/L]' + ,hu: 'Cukorszint választott tartomány [mg/dL,mmol/L]' } ,'Start of record validity' : { cs: 'Začátek platnosti záznamu' @@ -8849,6 +9218,7 @@ function init() { ,it: 'Inizio di validità del dato' ,tr: 'Kayıt geçerliliği başlangıcı' ,zh_cn: '有效记录开始' + ,hu: 'Bejegyzés kezdetének érvényessége' } ,'Icicle' : { cs: 'Rampouch' @@ -8860,7 +9230,7 @@ function init() { ,es: 'Inverso' ,ro: 'Țurțure' ,sv: 'Istapp' - ,nb: 'Isfjell' + ,nb: 'Istapp' ,fi: 'Jääpuikko' ,bg: 'Висящ' ,hr: 'Padajuće' @@ -8873,6 +9243,7 @@ function init() { ,tr: 'Buzsaçağı' //Sarkıt ,zh_cn: 'Icicle' ,zh_tw: 'Icicle' + ,hu: 'Inverzió' } ,'Render Basal' : { cs: 'Zobrazení bazálu' @@ -8898,6 +9269,7 @@ function init() { ,tr: 'Bazal Grafik' ,zh_cn: '使用基础率' ,zh_tw: '使用基礎率' + ,hu: 'Bazál megjelenítése' } ,'Profile used' : { cs: 'Použitý profil' @@ -8922,6 +9294,7 @@ function init() { ,it: 'Profilo usato' ,tr: 'Kullanılan profil' ,zh_cn: '配置文件已使用' + ,hu: 'Használatban lévő profil' } ,'Calculation is in target range.' : { cs: 'Kalkulace je v cílovém rozsahu.' @@ -8946,6 +9319,7 @@ function init() { ,it: 'Calcolo all\'interno dell\'intervallo' ,tr: 'Hesaplama hedef aralıktadır.' ,zh_cn: '预计在目标范围内' + ,hu: 'A számítás a cél tartományban található' } ,'Loading profile records ...' : { cs: 'Nahrávám profily ...' @@ -8970,6 +9344,7 @@ function init() { ,it: 'Caricamento dati del profilo ...' ,tr: 'Profil kayıtları yükleniyor ...' ,zh_cn: '载入配置文件记录...' + ,hu: 'Profil bejegyzéseinek betöltése...' } ,'Values loaded.' : { cs: 'Data nahrána.' @@ -8994,6 +9369,7 @@ function init() { ,it: 'Valori caricati.' ,tr: 'Değerler yüklendi.' ,zh_cn: '已载入数值' + ,hu: 'Értékek betöltése.' } ,'Default values used.' : { cs: 'Použity výchozí hodnoty.' @@ -9018,6 +9394,7 @@ function init() { ,it: 'Valori standard usati.' ,tr: 'Varsayılan değerler kullanıldı.' ,zh_cn: '已使用默认值' + ,hu: 'Alap értékek használva.' } ,'Error. Default values used.' : { cs: 'CHYBA: Použity výchozí hodnoty.' @@ -9042,6 +9419,7 @@ function init() { ,it: 'Errore. Valori standard usati.' ,tr: 'Hata. Varsayılan değerler kullanıldı.' ,zh_cn: '错误,已使用默认值' + ,hu: 'Hiba: Alap értékek használva' } ,'Time ranges of target_low and target_high don\'t match. Values are restored to defaults.' : { cs: 'Rozsahy časů pro limity glykémií si neodpovídají. Budou nastaveny výchozí hodnoty.' @@ -9066,6 +9444,7 @@ function init() { ,nl: 'Tijdspanne van laag en hoog doel zijn niet correct. Standaard waarden worden gebruikt' ,tr: 'Target_low ve target_high öğelerinin zaman aralıkları eşleşmiyor. Değerler varsayılanlara geri yüklendi.' ,zh_cn: '时间范围内的目标高低血糖值不匹配。已恢复使用默认值。' + ,hu: 'A cukorszint-cél időtartománya nem egyezik. Visszaállítás az alapértékekre' } ,'Valid from:' : { cs: 'Platné od:' @@ -9090,6 +9469,7 @@ function init() { ,it: 'Valido da:' ,tr: 'Tarihinden itibaren geçerli' ,zh_cn: '生效从:' + ,hu: 'Érvényes:' } ,'Save current record before switching to new?' : { cs: 'Uložit současný záznam před přepnutím na nový?' @@ -9114,7 +9494,8 @@ function init() { ,it: 'Salvare il dato corrente prima di passare ad uno nuovo?' ,tr: 'Yenisine geçmeden önce mevcut kaydı kaydet' ,zh_cn: '切换至新记录前保存当前记录?' - } + ,hu: 'Elmentsem az aktuális adatokat mielőtt újra válunk?' + } ,'Add new interval before' : { cs: 'Přidat nový interval před' ,he: 'הוסף מרווח חדש לפני ' @@ -9138,6 +9519,7 @@ function init() { ,it: 'Aggiungere prima un nuovo intervallo' ,tr: 'Daha önce yeni aralık ekle' ,zh_cn: '在此前新增区间' + ,hu: 'Új intervallum hozzáadása elötte' } ,'Delete interval' : { cs: 'Smazat interval' @@ -9162,6 +9544,7 @@ function init() { ,it: 'Elimina intervallo' ,tr: 'Aralığı sil' ,zh_cn: '删除区间' + ,hu: 'Intervallum törlése' } ,'I:C' : { cs: 'I:C' @@ -9185,6 +9568,7 @@ function init() { ,it: 'I:C' ,tr: 'İ:K' ,zh_cn: 'ICR' + ,hu: 'I:C' } ,'ISF' : { cs: 'ISF' @@ -9208,6 +9592,7 @@ function init() { ,it: 'ISF' ,tr: 'ISF' ,zh_cn: 'ISF' + ,hu: 'ISF' } ,'Combo Bolus' : { cs: 'Kombinovaný bolus' @@ -9232,6 +9617,7 @@ function init() { ,it: 'Combo Bolo' ,tr: 'Kombo (Yayma) Bolus' ,zh_cn: '双波' + ,hu: 'Kombinált bólus' } ,'Difference' : { cs: 'Rozdíl' @@ -9256,6 +9642,7 @@ function init() { ,it: 'Differenza' ,tr: 'fark' ,zh_cn: '差别' + ,hu: 'Különbség' } ,'New time' : { cs: 'Nový čas' @@ -9280,6 +9667,7 @@ function init() { ,it: 'Nuovo Orario' ,tr: 'Yeni zaman' ,zh_cn: '新时间' + ,hu: 'Új idő:' } ,'Edit Mode' : { cs: 'Editační mód' @@ -9306,6 +9694,7 @@ function init() { ,tr: 'Düzenleme Modu' ,zh_cn: '编辑模式' ,zh_tw: '編輯模式' + ,hu: 'Szerkesztési mód' } ,'When enabled icon to start edit mode is visible' : { cs: 'Pokud je povoleno, ikona pro vstup do editačního módu je zobrazena' @@ -9331,6 +9720,7 @@ function init() { ,tr: 'Etkinleştirildiğinde düzenleme modunun başında simgesi görünecektir.' ,zh_cn: '启用后开始编辑模式图标可见' ,zh_tw: '啟用後開始編輯模式圖標可見' + ,hu: 'Engedélyezés után a szerkesztési ikon látható' } ,'Operation' : { cs: 'Operace' @@ -9355,6 +9745,7 @@ function init() { ,it: 'Operazione' ,tr: 'İşlem' //Operasyon ,zh_cn: '操作' + ,hu: 'Operáció' } ,'Move' : { cs: 'Přesunout' @@ -9379,6 +9770,7 @@ function init() { ,it: 'Muovi' ,tr: 'Taşı' ,zh_cn: '移动' + ,hu: 'Áthelyezés' } ,'Delete' : { cs: 'Odstranit' @@ -9404,6 +9796,7 @@ function init() { ,ja: '削除' ,tr: 'Sil' ,zh_cn: '删除' + ,hu: 'Törlés' } ,'Move insulin' : { cs: 'Přesunout inzulín' @@ -9428,6 +9821,7 @@ function init() { ,it: 'Muovi Insulina' ,tr: 'İnsülini taşı' ,zh_cn: '移动胰岛素' + ,hu: 'Inzulin áthelyezése' } ,'Move carbs' : { cs: 'Přesunout sacharidy' @@ -9452,6 +9846,7 @@ function init() { ,it: 'Muovi carboidrati' ,tr: 'Karbonhidratları taşı' ,zh_cn: '移动碳水' + ,hu: 'Szénhidrát áthelyezése' } ,'Remove insulin' : { cs: 'Odstranit inzulín' @@ -9476,6 +9871,7 @@ function init() { ,it: 'Rimuovi insulina' ,tr: 'İnsülini kaldır' ,zh_cn: '去除胰岛素' + ,hu: 'Inzulin törlése' } ,'Remove carbs' : { cs: 'Odstranit sacharidy' @@ -9500,6 +9896,7 @@ function init() { ,it: 'Rimuovi carboidrati' ,tr: 'Karbonhidratları kaldır' ,zh_cn: '去除碳水' + ,hu: 'Szénhidrát törlése' } ,'Change treatment time to %1 ?' : { cs: 'Změnit čas ošetření na %1 ?' @@ -9524,6 +9921,7 @@ function init() { ,it: 'Cambiare tempo alla somministrazione a %1 ?' ,tr: 'Tedavi tarihini %1 e değiştirilsin mi?' ,zh_cn: '修改操作时间到%1?' + ,hu: 'A kezelés időpontjának áthelyezése %1?' } ,'Change carbs time to %1 ?' : { cs: 'Změnit čas sacharidů na %1 ?' @@ -9548,6 +9946,7 @@ function init() { ,it: 'Cambiare durata carboidrati a %1 ?' ,tr: 'Karbonhidrat zamanını %1 e değiştirilsin mi?' ,zh_cn: '修改碳水时间到%1?' + ,hu: 'Szénhidrát időpontjának áthelyezése %1' } ,'Change insulin time to %1 ?' : { cs: 'Změnit čas inzulínu na %1 ?' @@ -9572,6 +9971,7 @@ function init() { ,it: 'Cambiare durata insulina a %1 ?' ,tr: 'İnsülin tarihini %1 e değiştirilsin mi?' // zamanı ,zh_cn: '修改胰岛素时间到%1?' + ,hu: 'Inzulin időpont áthelyezése %1' } ,'Remove treatment ?' : { cs: 'Odstranit ošetření ?' @@ -9596,6 +9996,7 @@ function init() { ,it: 'Rimuovere somministrazione ?' ,tr: 'Tedavi kaldırılsın mı? ' ,zh_cn: '去除操作?' + ,hu: 'Kezelés törlése?' } ,'Remove insulin from treatment ?' : { cs: 'Odstranit inzulín z ošetření ?' @@ -9620,6 +10021,7 @@ function init() { ,it: 'Rimuovere insulina dalla somministrazione ?' ,tr: 'İnsülini tedaviden çıkartılsın mı?' ,zh_cn: '从操作中去除胰岛素?' + ,hu: 'Inzulin törlése a kezelésből?' } ,'Remove carbs from treatment ?' : { cs: 'Odstranit sacharidy z ošetření ?' @@ -9644,6 +10046,7 @@ function init() { ,it: 'Rimuovere carboidrati dalla somministrazione ?' ,tr: 'Karbonhidratları tedaviden çıkartılsın mı ?' // kaldırılsın mı ,zh_cn: '从操作中去除碳水化合物?' + ,hu: 'Szénhidrát törlése a kezelésből?' } ,'Rendering' : { cs: 'Vykresluji' @@ -9668,6 +10071,7 @@ function init() { ,it: 'Traduzione' ,tr: 'Grafik oluşturuluyor...' ,zh_cn: '渲染' + ,hu: 'Kirajzolás' } ,'Loading OpenAPS data of' : { cs: 'Nahrávám OpenAPS data z' @@ -9692,6 +10096,7 @@ function init() { ,nl: 'OpenAPS gegevens opladen van' ,tr: 'dan OpenAPS verileri yükleniyor' ,zh_cn: '载入OpenAPS数据从' + ,hu: 'OpenAPS adatainak betöltése innen' } ,'Loading profile switch data' : { cs: 'Nahrávám data přepnutí profilu' @@ -9716,6 +10121,7 @@ function init() { ,nl: 'Ophalen van data om profiel te wisselen' ,tr: 'Veri profili değişikliği yükleniyor' ,zh_cn: '载入配置文件交换数据' + ,hu: 'Profil változás adatainak betöltése' } ,'Redirecting you to the Profile Editor to create a new profile.' : { cs: 'Chybě nastavený profil.\nNení definovaný žádný platný profil k času zobrazení.\nProvádím přesměrování na editor profilu.' @@ -9740,6 +10146,7 @@ function init() { ,nl: 'Verkeerde profiel instellingen.\ngeen profiel beschibaar voor getoonde tijd.\nVerder naar profiel editor om een profiel te maken.' ,tr: 'Yanlış profil ayarı.\nGörüntülenen zamana göre profil tanımlanmamış.\nYeni profil oluşturmak için profil düzenleyicisine yönlendiriliyor.' ,zh_cn: '配置文件设置错误。\n没有配置文件定义为显示时间。\n返回配置文件编辑器以新建配置文件。' + ,hu: 'Átirányítás a profil szerkesztőre, hogy egy új profilt készítsen' } ,'Pump' : { cs: 'Pumpa' @@ -9764,6 +10171,7 @@ function init() { ,it: 'Pompa' ,tr: 'Pompa' ,zh_cn: '胰岛素泵' + ,hu: 'Pumpa' } ,'Sensor Age' : { cs: 'Stáří senzoru (SAGE)' @@ -9789,6 +10197,7 @@ function init() { ,tr: '(SAGE) Sensör yaşı ' ,zh_cn: '探头使用时间(SAGE)' ,zh_tw: '探頭使用時間(SAGE)' + ,hu: 'Szenzor élettartalma (SAGE)' } ,'Insulin Age' : { cs: 'Stáří inzulínu (IAGE)' @@ -9814,6 +10223,7 @@ function init() { ,tr: '(IAGE) İnsülin yaşı' ,zh_cn: '胰岛素使用时间(IAGE)' ,zh_tw: '胰島素使用時間(IAGE)' + ,hu: 'Inzulin élettartalma (IAGE)' } ,'Temporary target' : { cs: 'Dočasný cíl' @@ -9838,6 +10248,7 @@ function init() { ,it: 'Obiettivo Temporaneo' ,tr: 'Geçici hedef' ,zh_cn: '临时目标' + ,hu: 'Átmeneti cél' } ,'Reason' : { cs: 'Důvod' @@ -9862,6 +10273,7 @@ function init() { ,it: 'Ragionare' ,tr: 'Neden' // Gerekçe ,zh_cn: '原因' + ,hu: 'Indok' } ,'Eating soon' : { cs: 'Následuje jídlo' @@ -9885,6 +10297,7 @@ function init() { ,it: 'Mangiare prossimamente' ,tr: 'Yakında yemek' // Kısa zamanda yemek yenecek ,zh_cn: '接近用餐时间' + ,hu: 'Hamarosan eszem' } ,'Top' : { cs: 'Horní' @@ -9909,6 +10322,7 @@ function init() { ,tr: 'Üst' ,zh_cn: '顶部' ,pl: 'Góra' + ,hu: 'Felső' } ,'Bottom' : { cs: 'Dolní' @@ -9933,6 +10347,7 @@ function init() { ,tr: 'Alt' //aşağı, alt, düşük ,zh_cn: '底部' ,pl: "Dół" + ,hu: "Alsó" } ,'Activity' : { cs: 'Aktivita' @@ -9957,6 +10372,7 @@ function init() { ,tr: 'Aktivite' ,zh_cn: '有效的' ,pl: 'Aktywność' + ,hu: 'Aktivitás' } ,'Targets' : { cs: 'Cíl' @@ -9981,6 +10397,7 @@ function init() { ,tr: 'Hedefler' ,zh_cn: '目标' ,pl: 'Cele' + ,hu: 'Célok' } ,'Bolus insulin:' : { cs: 'Bolusový inzulín:' @@ -10005,6 +10422,7 @@ function init() { ,tr: 'Bolus insülin:' ,zh_cn: '大剂量胰岛素' ,pl: 'Bolus insuliny' + ,hu: 'Bólus inzulin' } ,'Base basal insulin:' : { cs: 'Základní bazální inzulín:' @@ -10029,6 +10447,7 @@ function init() { ,tr: 'Temel bazal insülin' ,zh_cn: '基础率胰岛素' ,pl: 'Bazowa dawka insuliny' + ,hu: 'Általános bazal inzulin' } ,'Positive temp basal insulin:' : { cs: 'Pozitivní dočasný bazální inzulín:' @@ -10053,6 +10472,7 @@ function init() { ,nl: 'Extra tijdelijke basaal insuline' ,tr: 'Pozitif geçici bazal insülin:' ,zh_cn: '实际临时基础率胰岛素' + ,hu: 'Pozitív átmeneti bazál inzulin' } ,'Negative temp basal insulin:' : { cs:'Negativní dočasný bazální inzulín:' @@ -10077,6 +10497,7 @@ function init() { ,nl: 'Negatieve tijdelijke basaal insuline' ,tr: 'Negatif geçici bazal insülin:' ,zh_cn: '其余临时基础率胰岛素' + ,hu: 'Negatív átmeneti bazál inzulin' } ,'Total basal insulin:' : { cs: 'Celkový bazální inzulín:' @@ -10101,6 +10522,7 @@ function init() { ,nl: 'Totaal basaal insuline' ,tr: 'Toplam bazal insülin:' ,zh_cn: '基础率胰岛素合计' + ,hu: 'Teljes bazál inzulin' } ,'Total daily insulin:' : { cs:'Celkový denní inzulín:' @@ -10125,6 +10547,7 @@ function init() { ,nl: 'Totaal dagelijkse insuline' ,tr: 'Günlük toplam insülin:' ,zh_cn: '每日胰岛素合计' + ,hu: 'Teljes napi inzulin' } ,'Unable to %1 Role' : { // PUT or POST cs: 'Chyba volání %1 Role:' @@ -10148,6 +10571,7 @@ function init() { ,nl: 'Kan %1 rol niet verwijderen' ,tr: '%1 Rolü yapılandırılamadı' ,zh_cn: '%1角色不可用' + ,hu: 'Hiba a %1 szabály hívásánál' } ,'Unable to delete Role' : { cs: 'Nelze odstranit Roli:' @@ -10171,6 +10595,7 @@ function init() { ,tr: 'Rol silinemedi' ,zh_cn: '无法删除角色' ,pl: 'Nie można usunąć roli' + ,hu: 'Nem lehetett a Szerepet törölni' } ,'Database contains %1 roles' : { cs: 'Databáze obsahuje %1 rolí' @@ -10194,6 +10619,7 @@ function init() { ,nl: 'Database bevat %1 rollen' ,tr: 'Veritabanı %1 rol içerir' ,zh_cn: '数据库包含%1个角色' + ,hu: 'Az adatbázis %1 szerepet tartalmaz' } ,'Edit Role' : { cs:'Editovat roli' @@ -10217,6 +10643,7 @@ function init() { ,nl: 'Pas rol aan' ,tr: 'Rolü düzenle' ,zh_cn: '编辑角色' + ,hu: 'Szerep szerkesztése' } ,'admin, school, family, etc' : { cs: 'administrátor, škola, rodina atd...' @@ -10240,6 +10667,7 @@ function init() { ,nl: 'admin, school, familie, etc' ,tr: 'yönetici, okul, aile, vb' ,zh_cn: '政府、学校、家庭等' + ,hu: 'admin, iskola, család, stb' } ,'Permissions' : { cs: 'Oprávnění' @@ -10263,6 +10691,7 @@ function init() { ,nl: 'Rechten' ,tr: 'İzinler' ,zh_cn: '权限' + ,hu: 'Engedély' } ,'Are you sure you want to delete: ' : { cs: 'Opravdu vymazat: ' @@ -10286,6 +10715,7 @@ function init() { ,nl: 'Weet u het zeker dat u wilt verwijderen?' ,tr: 'Silmek istediğinizden emin misiniz:' ,zh_cn: '你确定要删除:' + ,hu: 'Biztos, hogy törölni szeretnéd: ' } ,'Each role will have a 1 or more permissions. The * permission is a wildcard, permissions are a hierarchy using : as a separator.' : { cs: 'Každá role má 1 nebo více oprávnění. Oprávnění * je zástupný znak, oprávnění jsou hiearchie používající : jako oddělovač.' @@ -10308,6 +10738,7 @@ function init() { ,nl: 'Elke rol heeft mintens 1 machtiging. De * machtiging is een wildcard, machtigingen hebben een hyrarchie door gebruik te maken van : als scheidingsteken.' ,tr: 'Her rolün bir veya daha fazla izni vardır.*izni bir yer tutucudur ve izinler ayırıcı olarak : ile hiyerarşiktir.' ,zh_cn: '每个角色都具有一个或多个权限。权限设置时使用*作为通配符,层次结构使用:作为分隔符。' + ,hu: 'Minden szerepnek egy vagy több engedélye van. A * engedély helyettesítő engedély amely a hierarchiához : használja elválasztásnak.' } ,'Add new Role' : { cs: 'Přidat novou roli' @@ -10331,6 +10762,7 @@ function init() { ,tr: 'Yeni Rol ekle' ,zh_cn: '添加新角色' ,pl: 'Dodaj nową rolę' + ,hu: 'Új szerep hozzáadása' } ,'Roles - Groups of People, Devices, etc' : { cs: 'Role - Skupiny lidí, zařízení atd.' @@ -10354,6 +10786,7 @@ function init() { ,tr: 'Roller - İnsan grupları, Cihazlar vb.' ,zh_cn: '角色 - 一组人或设备等' ,pl: 'Role - Grupy ludzi, urządzeń, itp' + ,hu: 'Szerepek - Emberek csoportja, berendezések, stb.' } ,'Edit this role' : { cs: 'Editovat tuto roli' @@ -10377,6 +10810,7 @@ function init() { ,tr: 'Bu rolü düzenle' ,zh_cn: '编辑角色' ,pl: 'Edytuj rolę' + ,hu: 'Szerep szerkesztése' } ,'Admin authorized' : { cs: 'Admin autorizován' @@ -10401,6 +10835,7 @@ function init() { ,zh_cn: '已授权' ,zh_tw: '已授權' ,pl: 'Administrator autoryzowany' + ,hu: 'Adminisztrátor engedélyezve' } ,'Subjects - People, Devices, etc' : { cs: 'Subjekty - Lidé, zařízení atd.' @@ -10423,7 +10858,8 @@ function init() { ,nl: 'Onderwerpen - Mensen, apparaten etc' ,tr: 'Konular - İnsanlar, Cihazlar, vb.' ,zh_cn: '用户 - 人、设备等' - ,pl: 'Obiekty - ludzie, urządzenia itp' + ,pl: 'Obiekty - ludzie, urządzenia itp' + ,hu: 'Semélyek - Emberek csoportja, berendezések, stb.' } ,'Each subject will have a unique access token and 1 or more roles. Click on the access token to open a new view with the selected subject, this secret link can then be shared.' : { cs: 'Každý subjekt má svůj unikátní token a 1 nebo více rolí. Klikem na přístupový token se otevře nové okno pro tento subjekt. Tento link je možné sdílet.' @@ -10447,6 +10883,7 @@ function init() { ,tr: 'Her konu benzersiz bir erişim anahtarı ve bir veya daha fazla rol alır. Seçilen konuyla ilgili yeni bir görünüm elde etmek için erişim tuşuna tıklayın. Bu gizli bağlantı paylaşılabilinir.' ,zh_cn: '每个用户具有唯一的访问令牌和一个或多个角色。在访问令牌上单击打开新窗口查看已选择用户,此时该链接可分享。' ,pl: 'Każdy obiekt będzie miał unikalny token dostępu i jedną lub więcej ról. Kliknij token dostępu, aby otworzyć nowy widok z wybranym obiektem, ten tajny link może być następnie udostępniony' + ,hu: 'Mindegyik személynek egy egyedi hozzáférése lesz 1 vagy több szereppel. Kattints a tokenre, hogy egy új nézetet kapj - a kapott linket megoszthatod velük.' } ,'Add new Subject' : { cs: 'Přidat nový subjekt' @@ -10470,6 +10907,7 @@ function init() { ,tr: 'Yeni konu ekle' ,zh_cn: '添加新用户' ,pl: 'Dodaj obiekt' + ,hu: 'Új személy hozzáadása' } ,'Unable to %1 Subject' : { // PUT or POST cs: 'Chyba volání %1 Subjektu:' @@ -10493,6 +10931,7 @@ function init() { ,tr: '%1 konu yapılamıyor' ,zh_cn: '%1用户不可用' ,pl: 'Nie można %1 obiektu' + ,hu: 'A %1 személy hozáadása nem sikerült' } ,'Unable to delete Subject' : { cs: 'Nelze odstranit Subjekt:' @@ -10516,6 +10955,7 @@ function init() { ,tr: 'Konu silinemedi' ,zh_cn: '无法删除用户' ,pl: 'Nie można usunąć obiektu' + ,hu: 'A személyt nem sikerült törölni' } ,'Database contains %1 subjects' : { cs: 'Databáze obsahuje %1 subjektů' @@ -10539,6 +10979,7 @@ function init() { ,tr: 'Veritabanı %1 konu içeriyor' ,zh_cn: '数据库包含%1个用户' ,pl: 'Baza danych zawiera %1 obiektów' + ,hu: 'Az adatbázis %1 személyt tartalmaz' } ,'Edit Subject' : { cs:'Editovat subjekt' @@ -10562,6 +11003,7 @@ function init() { ,tr: 'Konuyu düzenle' ,zh_cn: '编辑用户' ,pl: 'Edytuj obiekt' + ,hu: 'Személy szerkesztése' } ,'person, device, etc' : { cs:'osoba, zařízeni atd.' @@ -10585,6 +11027,7 @@ function init() { ,tr: 'kişi, cihaz, vb' ,zh_cn: '人、设备等' ,pl: 'osoba, urządzenie, itp' + ,hu: 'személy, berendezés, stb.' } ,'role1, role2' : { cs:'role1, role2' @@ -10608,6 +11051,7 @@ function init() { ,tr: 'rol1, rol2' ,zh_cn: '角色1、角色2' ,pl: 'rola1, rola2' + ,hu: 'szerep1, szerep2' } ,'Edit this subject' : { cs:'Editovat tento subjekt' @@ -10631,6 +11075,7 @@ function init() { ,tr: 'Bu konuyu düzenle' ,zh_cn: '编辑此用户' ,pl: 'Edytuj ten obiekt' + ,hu: 'A kiválasztott személy szerkesztése' } ,'Delete this subject' : { cs:'Smazat tento subjekt' @@ -10654,6 +11099,7 @@ function init() { ,tr: 'Bu konuyu sil' ,zh_cn: '删除此用户' ,pl: 'Usuń ten obiekt' + ,hu: 'A kiválasztott személy törlése' } ,'Roles' : { cs:'Role' @@ -10677,6 +11123,7 @@ function init() { ,tr: 'Roller' ,zh_cn: '角色' ,pl: 'Role' + ,hu: 'Szerepek' } ,'Access Token' : { cs:'Přístupový token' @@ -10700,6 +11147,7 @@ function init() { ,tr: 'Erişim Simgesi (Access Token)' ,zh_cn: '访问令牌' ,pl: 'Token dostępu' + ,hu: 'Hozzáférési token' } ,'hour ago' : { cs:'hodina zpět' @@ -10723,6 +11171,7 @@ function init() { ,tr: 'saat önce' ,zh_cn: '小时前' ,pl: 'Godzię temu' + ,hu: 'órája' } ,'hours ago' : { cs:'hodin zpět' @@ -10746,6 +11195,7 @@ function init() { ,tr: 'saat önce' ,zh_cn: '小时前' ,pl: 'Godzin temu' + ,hu: 'órája' } ,'Silence for %1 minutes' : { cs:'Ztlumit na %1 minut' @@ -10770,6 +11220,7 @@ function init() { ,zh_cn: '静音%1分钟' ,zh_tw: '靜音%1分鐘' ,pl: 'Wycisz na %1 minut' + ,hul: 'Lehalkítás %1 percre' } ,'Check BG' : { cs:'Zkontrolovat glykémii' @@ -10793,6 +11244,7 @@ function init() { ,tr: 'KŞ\'ini kontrol et' ,zh_cn: '测量血糖' ,pl: 'Sprawdź glukozę z krwi' + ,hu: 'Ellenőrizd a cukorszintet' } ,'BASAL' : { cs: 'BAZÁL' @@ -10817,6 +11269,7 @@ function init() { ,zh_cn: '基础率' ,zh_tw: '基礎率' ,pl: 'BAZA' + ,hu: 'BAZÁL' } ,'Current basal' : { cs:'Současný bazál' @@ -10840,6 +11293,7 @@ function init() { ,tr: 'Geçerli Bazal' ,zh_cn: '当前基础率' ,pl: 'Dawka podstawowa' + ,hu: 'Aktuális bazál' } ,'Sensitivity' : { cs:'Citlivost (ISF)' @@ -10863,6 +11317,7 @@ function init() { ,tr: 'Duyarlılık Faktörü (ISF)' ,zh_cn: '胰岛素敏感系数' ,pl: 'Wrażliwość' + ,hu: 'Inzulin érzékenység' } ,'Current Carb Ratio' : { cs:'Sacharidový poměr (I:C)' @@ -10886,6 +11341,7 @@ function init() { ,tr: 'Geçerli Karbonhidrat oranı I/C (ICR)' ,zh_cn: '当前碳水化合物系数' ,pl: 'Obecny przelicznik węglowodanowy' + ,hu: 'Aktuális szénhidrát arány' } ,'Basal timezone' : { cs:'Časová zóna' @@ -10909,6 +11365,7 @@ function init() { ,tr: 'Bazal saat dilimi' ,zh_cn: '基础率时区' ,pl: 'Strefa czasowa dawki podstawowej' + ,hu: 'Bazál időzóna' } ,'Active profile' : { cs:'Aktivní profil' @@ -10932,6 +11389,7 @@ function init() { ,tr: 'Aktif profil' ,zh_cn: '当前配置文件' ,pl: 'Profil aktywny' + ,hu: 'Aktív profil' } ,'Active temp basal' : { cs:'Aktivní dočasný bazál' @@ -10955,6 +11413,7 @@ function init() { ,tr: 'Aktif geçici bazal oranı' ,zh_cn: '当前临时基础率' ,pl: 'Aktywa tymczasowa dawka podstawowa' + ,hu: 'Aktív átmeneti bazál' } ,'Active temp basal start' : { cs:'Začátek dočasného bazálu' @@ -10978,6 +11437,7 @@ function init() { ,tr: 'Aktif geçici bazal oranı başlangıcı' ,zh_cn: '当前临时基础率开始' ,pl: 'Start aktywnej tymczasowej dawki podstawowej' + ,hu: 'Aktív átmeneti bazál kezdete' } ,'Active temp basal duration' : { cs:'Trvání dočasného bazálu' @@ -11001,6 +11461,7 @@ function init() { ,zh_cn: '当前临时基础率期间' ,pl: 'Czas trwania aktywnej tymczasowej dawki podstawowej' ,tr: 'Aktif geçici bazal süresi' + ,hu: 'Aktív átmeneti bazál időtartalma' } ,'Active temp basal remaining' : { cs:'Zbývající dočasný bazál' @@ -11024,6 +11485,7 @@ function init() { ,zh_cn: '当前临时基础率剩余' ,pl: 'Pozostała aktywna tymczasowa dawka podstawowa' ,tr: 'Aktif geçici bazal kalan' + ,hu: 'Átmeneti bazál visszamaradó ideje' } ,'Basal profile value' : { cs: 'Základní hodnota bazálu' @@ -11047,6 +11509,7 @@ function init() { ,zh_cn: '基础率配置文件值' ,pl: 'Wartość profilu podstawowego' ,tr: 'Bazal profil değeri' + ,hu: 'Bazál profil értéke' } ,'Active combo bolus' : { cs:'Aktivní kombinovaný bolus' @@ -11070,6 +11533,7 @@ function init() { ,zh_cn: '当前双波大剂量' ,pl: 'Aktywny bolus złożony' ,tr: 'Aktive kombo bolus' + ,hu: 'Aktív kombinált bólus' } ,'Active combo bolus start' : { cs: 'Začátek kombinovaného bolusu' @@ -11093,6 +11557,7 @@ function init() { ,zh_cn: '当前双波大剂量开始' ,pl: 'Start aktywnego bolusa złożonego' ,tr: 'Aktif gecikmeli bolus başlangıcı' + ,hu: 'Aktív kombinált bólus kezdete' } ,'Active combo bolus duration' : { cs: 'Trvání kombinovaného bolusu' @@ -11116,6 +11581,7 @@ function init() { ,zh_cn: '当前双波大剂量期间' ,pl: 'Czas trwania aktywnego bolusa złożonego' ,tr: 'Active combo bolus süresi' + ,hu: 'Aktív kombinált bólus időtartalma' } ,'Active combo bolus remaining' : { cs: 'Zbývající kombinovaný bolus' @@ -11139,6 +11605,7 @@ function init() { ,zh_cn: '当前双波大剂量剩余' ,pl: 'Pozostały aktywny bolus złożony' ,tr: 'Aktif kombo (yayım) bolus kaldı' + ,hu: 'Aktív kombinált bólus fennmaradó idő' } ,'BG Delta' : { cs:'Změna glykémie' @@ -11163,6 +11630,7 @@ function init() { ,zh_tw: '血糖增量' ,pl: 'Zmiana glikemii' ,tr: 'KŞ farkı' + ,hu: 'Cukorszint változása' } ,'Elapsed Time' : { cs:'Dosažený čas' @@ -11187,6 +11655,7 @@ function init() { ,zh_tw: '所需時間' ,pl: 'Upłynął czas' ,tr: 'Geçen zaman' + ,hu: 'Eltelt idő' } ,'Absolute Delta' : { cs:'Absolutní rozdíl' @@ -11211,6 +11680,7 @@ function init() { ,zh_tw: '絕對增量' ,pl: 'różnica absolutna' ,tr: 'Mutlak fark' + ,hu: 'Abszolút külonbség' } ,'Interpolated' : { cs:'Interpolováno' @@ -11235,6 +11705,7 @@ function init() { ,zh_tw: '插值' ,pl: 'Interpolowany' ,tr: 'Aralıklı' + ,hu: 'Interpolált' } ,'BWP' : { // Bolus Wizard Preview cs: 'KALK' @@ -11259,6 +11730,7 @@ function init() { ,zh_tw: 'BWP' ,pl: 'Kalkulator bolusa' ,tr: 'BWP' + ,hu: 'BWP' } ,'Urgent' : { cs:'Urgentní' @@ -11284,6 +11756,7 @@ function init() { ,zh_tw: '緊急' ,pl:'Pilny' ,tr: 'Acil' + ,hu: 'Sűrgős' } ,'Warning' : { cs:'Varování' @@ -11308,6 +11781,7 @@ function init() { ,zh_tw: '警告' ,pl: 'Ostrzeżenie' ,tr: 'Uyarı' + ,hu: 'Figyelmeztetés' } ,'Info' : { cs: 'Informativní' @@ -11332,6 +11806,7 @@ function init() { ,zh_tw: '資訊' ,pl: 'Informacja' ,tr: 'Info' + ,hu: 'Információ' } ,'Lowest' : { cs: 'Nejnižší' @@ -11356,6 +11831,7 @@ function init() { ,zh_cn: '血糖极低' ,zh_tw: '血糖極低' ,pl: 'Niski' + ,hu: 'Legalacsonyabb' } ,'Snoozing high alarm since there is enough IOB' : { cs:'Vypínání alarmu vyskoké glykémie, protože je dostatek IOB' @@ -11379,6 +11855,7 @@ function init() { ,tr: 'Yeterli IOB(Aktif İnsülin) olduğundan KŞ yüksek uyarımını ertele' ,zh_cn: '有足够的IOB(活性胰岛素),暂停高血糖警报' ,pl: 'Wycisz alarm wysokiej glikemi, jest wystarczająco dużo aktywnej insuliny' + ,hu: 'Magas cukor riasztás késleltetése mivel elegendő inzulin van kiadva (IOB)' } ,'Check BG, time to bolus?' : { cs:'Zkontrolovat glykémii, čas na bolus?' @@ -11402,6 +11879,7 @@ function init() { ,tr: 'KŞine bakın, gerekirse bolus verin?' ,zh_cn: '测量血糖,该输注大剂量了?' ,pl: 'Sprawdź glikemię, czas na bolusa ?' + ,hu: 'Ellenőrizd a cukorszintet. Ideje bóluszt adni?' } ,'Notice' : { cs:'Poznámka' @@ -11425,6 +11903,7 @@ function init() { ,tr: 'Not' ,zh_cn: '提示' ,pl: 'Uwaga' + ,hu: 'Megjegyzés' } ,'required info missing' : { cs:'chybějící informace' @@ -11448,6 +11927,7 @@ function init() { ,tr: 'gerekli bilgi eksik' ,zh_cn: '所需信息不全' ,pl: 'brak wymaganych informacji' + ,hu: 'Szükséges információ hiányos' } ,'Insulin on Board' : { cs:'Aktivní inzulín' @@ -11471,6 +11951,7 @@ function init() { ,tr: '(IOB) Aktif İnsülin' ,zh_cn: '活性胰岛素(IOB)' ,pl: 'Aktywna insulina' + ,hu: 'Aktív inzulin (IOB)' } ,'Current target' : { cs:'Aktuální cílová hodnota' @@ -11494,6 +11975,7 @@ function init() { ,tr: 'Mevcut hedef' ,zh_cn: '当前目标' ,pl: 'Aktualny cel' + ,hu: 'Jelenlegi cél' } ,'Expected effect' : { cs:'Očekávaný efekt' @@ -11517,6 +11999,7 @@ function init() { ,tr: 'Beklenen etki' ,zh_cn: '预期效果' ,pl: 'Oczekiwany efekt' + ,hu: 'Elvárt efektus' } ,'Expected outcome' : { cs:'Očekávaný výsledek' @@ -11540,6 +12023,7 @@ function init() { ,tr: 'Beklenen sonuç' ,zh_cn: '预期结果' ,pl: 'Oczekowany resultat' + ,hu: 'Elvárt eredmény' } ,'Carb Equivalent' : { cs:'Ekvivalent v sacharidech' @@ -11563,6 +12047,7 @@ function init() { ,tr: 'Karbonhidrat eşdeğeri' ,zh_cn: '碳水当量' ,pl: 'Odpowiednik w węglowodanach' + ,hu: 'Szénhidrát megfelelője' } ,'Excess insulin equivalent %1U more than needed to reach low target, not accounting for carbs' : { cs:'Nadbytek inzulínu: o %1U více, než na dosažení spodní hranice cíle. Nepočítáno se sacharidy.' @@ -11586,6 +12071,7 @@ function init() { ,it: 'L\'eccesso d\'insulina equivalente %1U più che necessari per raggiungere l\'obiettivo basso, non rappresentano i carboidrati.' ,tr: 'Fazla insülin: Karbonhidratları dikkate alınmadan, alt hedefe ulaşmak için gerekenden %1U\'den daha fazla' //??? ,zh_cn: '胰岛素超过至血糖下限目标所需剂量%1单位,不计算碳水化合物' + ,hu: 'Felesleges inzulin megegyező %1U egységgel az alacsony cél eléréséhez, nem számolva a szénhidrátokkal' } ,'Excess insulin equivalent %1U more than needed to reach low target, MAKE SURE IOB IS COVERED BY CARBS' : { cs:'Nadbytek inzulínu: o %1U více, než na dosažení spodní hranice cíle. UJISTĚTE SE, ŽE JE TO POKRYTO SACHARIDY' @@ -11609,6 +12095,7 @@ function init() { ,tr: 'Fazla insülin: Alt KŞ hedefine ulaşmak için gerekenden %1 daha fazla insülin.IOB(Aktif İnsülin) Karbonhidrat tarafından karşılandığından emin olun.' ,zh_cn: '胰岛素超过至血糖下限目标所需剂量%1单位,确认IOB(活性胰岛素)被碳水化合物覆盖' ,pl: 'Nadmiar insuliny: o %1J więcej niż potrzeba, aby osiągnąć cel dolnej granicy. UPEWNIJ SIĘ, ŻE AKTYWNA INSULINA JEST POKRYTA WĘGLOWODANAMI' + ,hu: 'Felesleges inzulin megegyező %1U egységgel az alacsony cél eléréséhez. FONTOS, HOGY A IOB LEGYEN SZÉNHIDRÁTTAL TAKARVA' } ,'%1U reduction needed in active insulin to reach low target, too much basal?' : { cs:'Nutné snížení aktivního inzulínu o %1U k dosažení spodního cíle. Příliž mnoho bazálu?' @@ -11632,6 +12119,7 @@ function init() { ,tr: 'Alt KŞ hedefi için %1U aktif insülin azaltılmalı, bazal oranı çok mu yüksek?' ,zh_cn: '活性胰岛素已可至血糖下限目标,需减少%1单位,基础率过高?' ,pl: '%1J potrzebnej redukcji w aktywnej insulinie, aby osiągnąć niski cel dolnej granicy, Za duża dawka podstawowa ?' + ,hu: '%1U egységnyi inzulin redukció szükséges az alacsony cél eléréséhez, túl magas a bazál?' } ,'basal adjustment out of range, give carbs?' : { cs:'úprava změnou bazálu není možná. Podat sacharidy?' @@ -11655,6 +12143,7 @@ function init() { ,tr: 'Bazal oran ayarlaması limit dışı, karbonhidrat alınsın mı?' ,zh_cn: '基础率调整在范围之外,需要碳水化合物?' ,pl: 'dawka podstawowa poza zakresem, podać węglowodany?' + ,hu: 'bazál változtatása az arányokon kívül esik, szénhidrát bevitele?' } ,'basal adjustment out of range, give bolus?' : { cs:'úprava změnou bazálu není možná. Podat bolus?' @@ -11678,6 +12167,7 @@ function init() { ,tr: 'Bazal oran ayarlaması limit dışı, bolus alınsın mı?' ,zh_cn: '基础率调整在范围之外,需要大剂量?' ,pl: 'dawka podstawowa poza zakresem, podać insulinę?' + ,hu: 'bazál változtatása az arányokon kívül esik, bólusz beadása?' } ,'above high' : { cs:'nad horním' @@ -11702,6 +12192,7 @@ function init() { ,zh_cn: '血糖过高' ,zh_tw: '血糖過高' ,pl: 'powyżej wysokiego' + ,hu: 'magas felett' } ,'below low' : { cs:'pod spodním' @@ -11726,6 +12217,7 @@ function init() { ,zh_cn: '血糖过低' ,zh_tw: '血糖過低' ,pl: 'poniżej niskiego' + ,hu: 'alacsony alatt' } ,'Projected BG %1 target' : { cs:'Předpokládaná glykémie %1 cílem' @@ -11749,6 +12241,7 @@ function init() { ,tr: 'Beklenen KŞ %1 hedefi' ,zh_cn: '预计血糖%1目标' ,pl: 'Oczekiwany poziom glikemii %1' + ,hu: 'Kiszámított BG cél %1' } ,'aiming at' : { cs:'s cílem' @@ -11772,6 +12265,7 @@ function init() { ,tr: 'istenen sonuç' ,zh_cn: '目标在' ,pl: 'pożądany wynik' + ,hu: 'cél' } ,'Bolus %1 units' : { cs:'Bolus %1 jednotek' @@ -11795,6 +12289,7 @@ function init() { ,tr: 'Bolus %1 Ünite' ,zh_cn: '大剂量%1单位' ,pl: 'Bolus %1 jednostek' + ,hu: 'Bólus %1 egységet' } ,'or adjust basal' : { cs:'nebo úprava bazálu' @@ -11818,6 +12313,7 @@ function init() { ,tr: 'ya da bazal ayarlama' ,zh_cn: '或调整基础率' ,pl: 'lub dostosuj dawkę bazową' + ,hu: 'vagy a bazál változtatása' } ,'Check BG using glucometer before correcting!' : { cs:'Před korekcí zkontrolujte glukometrem glykémii!' @@ -11841,6 +12337,7 @@ function init() { ,zh_cn: '校正前请使用血糖仪测量血糖!' ,pl: 'Sprawdź glikemię z krwi przed podaniem korekty!' ,tr: 'Düzeltme bolusu öncesi glikometreyle parmaktan KŞini kontrol edin!' + ,hu: 'Ellenőrizd a cukorszintet mérővel korrekció előtt!' } ,'Basal reduction to account %1 units:' : { cs:'Úprava bazálu pro náhradu bolusu %1 U ' @@ -11864,6 +12361,7 @@ function init() { ,zh_cn: '基础率减少到%1单位' ,pl: 'Dawka bazowa zredukowana do 1% J' ,tr: '%1 birimi telafi etmek için azaltılmış Bazaloranı:' + ,hu: 'A bazál csökkentése %1 egység kiszámításához:' } ,'30m temp basal' : { cs:'30ti minutový dočasný bazál' @@ -11887,6 +12385,7 @@ function init() { ,zh_cn: '30分钟临时基础率' ,pl: '30 minut tymczasowej dawki bazowej' ,tr: '30 dk. geçici Bazal ' + ,hu: '30p általános bazál' } ,'1h temp basal' : { cs:'hodinový dočasný bazál' @@ -11910,6 +12409,7 @@ function init() { ,zh_cn: '1小时临时基础率' ,pl: '1 godzina tymczasowej dawki bazowej' ,tr: '1 sa. geçici bazal' + ,hu: '10 általános bazál' } ,'Cannula change overdue!' : { cs:'Čas na výměnu set vypršel!' @@ -11933,6 +12433,7 @@ function init() { ,zh_cn: '超过更换管路的时间' ,pl: 'Przekroczono czas wymiany wkłucia!' ,tr: 'Kanül değişimi gecikmiş!' + ,hu: 'Kanil cseréjének ideje elmúlt' } ,'Time to change cannula' : { cs:'Čas na výměnu setu' @@ -11956,6 +12457,7 @@ function init() { ,zh_cn: '已到更换管路的时间' ,pl: 'Czas do wymiany wkłucia' ,tr: 'Kanül değiştirme zamanı' + ,hu: 'Ideje kicserélni a kanilt' } ,'Change cannula soon' : { cs:'Blíží se čas na výměnu setu' @@ -11978,6 +12480,7 @@ function init() { ,zh_cn: '接近更换管路的时间' ,pl: 'Wkrótce wymiana wkłucia' ,tr: 'Yakında kanül değiştirin' + ,hu: 'Hamarosan cseréld ki a kanilt' } ,'Cannula age %1 hours' : { cs:'Stáří setu %1 hodin' @@ -12001,6 +12504,7 @@ function init() { ,zh_cn: '管路已使用%1小时' ,pl: 'Czas od wymiany wkłucia %1 godzin' ,tr: 'Kanül yaşı %1 saat' + ,hu: 'Kamil életkora %1 óra' } ,'Inserted' : { cs:'Nasazený' @@ -12025,6 +12529,7 @@ function init() { ,zh_tw: '已植入' ,pl: 'Zamontowano' ,tr: 'Yerleştirilmiş' + ,hu: 'Behelyezve' } ,'CAGE' : { @@ -12050,6 +12555,7 @@ function init() { ,zh_tw: '管路' ,pl: 'Wiek wkłucia' ,tr: 'CAGE' + ,hu: 'CAGE' } ,'COB' : { cs:'SACH' @@ -12073,6 +12579,7 @@ function init() { ,zh_cn: '活性碳水COB' ,pl: 'Aktywne węglowodany' ,tr: 'COB' + ,hu: 'COB' } ,'Last Carbs' : { cs:'Poslední sacharidy' @@ -12096,6 +12603,7 @@ function init() { ,zh_cn: '上次碳水' ,pl: 'Ostatnie węglowodany' ,tr: 'Son Karbonhidrat' + ,hu: 'Utolsó szénhidrátok' } ,'IAGE' : { cs:'INZ' @@ -12120,6 +12628,7 @@ function init() { ,zh_tw: '胰島素' ,pl: 'Wiek insuliny' ,tr: 'IAGE' + ,hu: 'IAGE' } ,'Insulin reservoir change overdue!' : { cs:'Čas na výměnu zásobníku vypršel!' @@ -12143,6 +12652,7 @@ function init() { ,zh_cn: '超过更换胰岛素储液器的时间' ,pl: 'Przekroczono czas wymiany zbiornika na insulinę!' ,tr: 'İnsülin rezervuarı değişimi gecikmiş!' + ,hu: 'Inzulin tartály cseréjének ideje elmúlt' } ,'Time to change insulin reservoir' : { cs:'Čas na výměnu zásobníku' @@ -12166,6 +12676,7 @@ function init() { ,zh_cn: '已到更换胰岛素储液器的时间' ,pl: 'Czas do zmiany zbiornika na insulinę!' ,tr: 'İnsülin rezervuarını değiştirme zamanı!' + ,hu: 'Itt az ideje az inzulin tartály cseréjének' } ,'Change insulin reservoir soon' : { cs:'Blíží se čas na výměnu zásobníku' @@ -12189,6 +12700,7 @@ function init() { ,zh_cn: '接近更换胰岛素储液器的时间' ,pl: 'Wkrótce wymiana zbiornika na insulinę!' ,tr: 'Yakında insülin rezervuarını değiştirin' + ,hu: 'Hamarosan cseréld ki az inzulin tartályt' } ,'Insulin reservoir age %1 hours' : { cs:'Stáří zásobníku %1 hodin' @@ -12212,6 +12724,7 @@ function init() { ,zh_cn: '胰岛素储液器已使用%1小时' ,pl: 'Wiek zbiornika na insulinę %1 godzin' ,tr: 'İnsülin rezervuar yaşı %1 saat' + ,hu: 'Az inzulin tartály %1 órája volt cserélve' } ,'Changed' : { cs:'Vyměněno' @@ -12235,6 +12748,7 @@ function init() { ,zh_cn: '已更换' ,pl: 'Wymieniono' ,tr: 'Değişmiş' + ,hu: 'Cserélve' } ,'IOB' : { cs:'IOB' @@ -12258,6 +12772,7 @@ function init() { ,zh_cn: '活性胰岛素IOB' ,pl: 'Aktywna insulina' ,tr: 'IOB' + ,hu: 'IOB' } ,'Careportal IOB' : { cs:'IOB z ošetření' @@ -12281,6 +12796,7 @@ function init() { ,zh_cn: '服务面板IOB(活性胰岛素)' ,pl: 'Aktywna insulina z portalu' ,tr: 'Careportal IOB (Aktif İnsülin)' + ,hu: 'Careportal IOB érték' } ,'Last Bolus' : { cs:'Poslední bolus' @@ -12304,6 +12820,7 @@ function init() { ,zh_cn: '上次大剂量' ,pl: 'Ostatni bolus' ,tr: 'Son Bolus' + ,hu: 'Utolsó bólus' } ,'Basal IOB' : { cs:'IOB z bazálů' @@ -12327,6 +12844,7 @@ function init() { ,zh_cn: '基础率IOB(活性胰岛素)' ,pl: 'Aktywna insulina z dawki bazowej' ,tr: 'Bazal IOB' + ,hu: 'Bazál IOB' } ,'Source' : { cs:'Zdroj' @@ -12350,6 +12868,7 @@ function init() { ,zh_cn: '来源' ,pl: 'Źródło' ,tr: 'Kaynak' + ,hu: 'Forrás' } ,'Stale data, check rig?' : { cs:'Zastaralá data, zkontrolovat mobil?' @@ -12373,6 +12892,7 @@ function init() { ,nl: 'Geen data, controleer uploader' ,zh_cn: '数据过期,检查一下设备?' ,tr: 'Veri güncel değil, vericiyi kontrol et?' + ,hu: 'Öreg adatok, ellenőrizd a feltöltőt' } ,'Last received:' : { cs:'Naposledy přijato:' @@ -12396,6 +12916,7 @@ function init() { ,zh_cn: '上次接收:' ,pl: 'Ostatnio odebrane:' ,tr: 'Son alınan:' + ,hu: 'Utóljára fogadott:' } ,'%1m ago' : { cs:'%1m zpět' @@ -12419,6 +12940,7 @@ function init() { ,zh_cn: '%1分钟前' ,pl: '%1 minut temu' ,tr: '%1 dk. önce' + ,hu: '%1p ezelőtt' } ,'%1h ago' : { cs:'%1h zpět' @@ -12442,6 +12964,7 @@ function init() { ,zh_cn: '%1小时前' ,pl: '%1 godzin temu' ,tr: '%1 sa. önce' + ,hu: '%1ó ezelőtt' } ,'%1d ago' : { cs:'%1d zpět' @@ -12465,6 +12988,7 @@ function init() { ,zh_cn: '%1天前' ,pl: '%1 dni temu' ,tr: '%1 gün önce' + ,hu: '%1n ezelőtt' } ,'RETRO' : { cs:'RETRO' @@ -12488,6 +13012,7 @@ function init() { ,zh_cn: '历史数据' ,pl: 'RETRO' ,tr: 'RETRO Geçmiş' + ,hu: 'RETRO' } ,'SAGE' : { cs:'SENZ' @@ -12512,6 +13037,7 @@ function init() { ,zh_tw: '探頭' ,pl: 'Wiek sensora' ,tr: 'SAGE' + ,hu: 'SAGE' } ,'Sensor change/restart overdue!' : { cs:'Čas na výměnu senzoru vypršel!' @@ -12535,6 +13061,7 @@ function init() { ,zh_cn: '超过更换/重启探头的时间' ,pl: 'Przekroczono czas wymiany/restartu sensora!' ,tr: 'Sensör değişimi/yeniden başlatma gecikti!' + ,hu: 'Szenzor cseréjének / újraindításának ideje lejárt' } ,'Time to change/restart sensor' : { cs:'Čas na výměnu senzoru' @@ -12558,6 +13085,7 @@ function init() { ,zh_cn: '已到更换/重启探头的时间' ,pl: 'Czas do wymiany/restartu sensora' ,tr: 'Sensörü değiştirme/yeniden başlatma zamanı' + ,hu: 'Ideje a szenzort cserélni / újraindítani' } ,'Change/restart sensor soon' : { cs:'Blíží se čas na výměnu senzoru' @@ -12581,6 +13109,7 @@ function init() { ,zh_cn: '接近更换/重启探头的时间' ,pl: 'Wkrótce czas wymiany/restartu sensora' ,tr: 'Sensörü yakında değiştir/yeniden başlat' + ,hu: 'Hamarosan indítsd újra vagy cseréld ki a szenzort' } ,'Sensor age %1 days %2 hours' : { cs:'Stáří senzoru %1 dní %2 hodin' @@ -12604,6 +13133,7 @@ function init() { ,zh_cn: '探头使用了%1天%2小时' ,pl: 'Wiek sensora: %1 dni %2 godzin' ,tr: 'Sensör yaşı %1 gün %2 saat' + ,hu: 'Szenzor ideje %1 nap és %2 óra' } ,'Sensor Insert' : { cs: 'Výměna sensoru' @@ -12627,6 +13157,7 @@ function init() { ,zh_cn: '植入探头' ,pl: 'Zamontuj sensor' ,tr: 'Sensor yerleştirme' + ,hu: 'Szenzor behelyezve' } ,'Sensor Start' : { cs: 'Znovuspuštění sensoru' @@ -12650,6 +13181,7 @@ function init() { ,nl: 'Sensor start' ,zh_cn: '启动探头' ,tr: 'Sensör başlatma' + ,hu: 'Szenzor indítása' } ,'days' : { cs: 'dní' @@ -12673,6 +13205,7 @@ function init() { ,zh_cn: '天' ,pl: 'dni' ,tr: 'Gün' + ,hu: 'napok' } ,'Insulin distribution' : { cs: 'Rozložení inzulínu' @@ -12693,6 +13226,7 @@ function init() { ,hr: 'Raspodjela inzulina' ,pl: 'podawanie insuliny' ,tr: 'İnsülin dağılımı' + ,hu: 'Inzulin disztribúció' } ,'To see this report, press SHOW while in this view' : { cs: 'Pro zobrazení toho výkazu stiskněte Zobraz na této záložce' @@ -12713,6 +13247,7 @@ function init() { ,hr: 'Za prikaz ovog izvješća, pritisnite PRIKAŽI na ovom prozoru' ,pl: 'Aby wyświetlić ten raport, naciśnij przycisk POKAŻ w tym widoku' ,tr: 'Bu raporu görmek için bu görünümde GÖSTER düğmesine basın.' + ,hu: 'A jelentés megtekintéséhez kattints a MUTASD gombra' } ,'AR2 Forecast' : { cs: 'AR2 predikci' @@ -12733,6 +13268,7 @@ function init() { ,hr: 'AR2 procjena' ,pl: 'Prognoza AR2' ,tr: 'AR2 Tahmini' + ,hu: 'AR2 előrejelzés' } ,'OpenAPS Forecasts' : { cs: 'OpenAPS predikci' @@ -12753,6 +13289,7 @@ function init() { ,hr: 'OpenAPS prognoze' ,pl: 'Prognoza OpenAPS' ,tr: 'OpenAPS Tahminleri' + ,hu: 'OpenAPS előrejelzés' } ,'Temporary Target' : { cs: 'Dočasný cíl glykémie' @@ -12773,6 +13310,7 @@ function init() { ,hr: 'Privremeni cilj' ,pl: 'Cel tymczasowy' ,tr: 'Geçici Hedef' + ,hu: 'Átmeneti cél' } ,'Temporary Target Cancel' : { cs: 'Dočasný cíl glykémie konec' @@ -12793,6 +13331,7 @@ function init() { ,hr: 'Otkaz privremenog cilja' ,pl: 'Zel tymczasowy anulowany' ,tr: 'Geçici Hedef İptal' + ,hu: 'Átmeneti cél törlése' } ,'OpenAPS Offline' : { cs: 'OpenAPS vypnuto' @@ -12813,6 +13352,7 @@ function init() { ,hr: 'OpenAPS odspojen' ,pl: 'OpenAPS nieaktywny' ,tr: 'OpenAPS Offline (çevrimdışı)' + ,hu: 'OpenAPS nem elérhető (offline)' } ,'Profiles' : { cs: 'Profily' @@ -12833,6 +13373,7 @@ function init() { ,hr: 'Profili' ,pl: 'Profile' ,tr: 'Profiller' + ,hu: 'Profilok' } ,'Time in fluctuation' : { cs: 'Doba měnící se glykémie' @@ -12853,6 +13394,7 @@ function init() { ,hr: 'Vrijeme u fluktuaciji' ,pl: 'Czas fluaktacji (odchyleń)' ,tr: 'Dalgalanmada geçen süre' + ,hu: 'Kilengésben töltött idő' } ,'Time in rapid fluctuation' : { cs: 'Doba rychle se měnící glykémie' @@ -12873,6 +13415,7 @@ function init() { ,hr: 'Vrijeme u brzoj fluktuaciji' ,pl: 'Czas szybkich fluaktacji (odchyleń)' ,tr: 'Hızlı dalgalanmalarda geçen süre' + ,hu: 'Magas kilengésekben töltött idő' } ,'This is only a rough estimation that can be very inaccurate and does not replace actual blood testing. The formula used is taken from:' : { cs: 'Toto je pouze hrubý odhad, který může být nepřesný a nenahrazuje kontrolu z krve. Vzorec je převzatý z:' @@ -12893,6 +13436,7 @@ function init() { ,hr: 'Ovo je samo gruba procjena koja može biti neprecizna i ne mijenja testiranje iz krvi. Formula je uzeta iz:' ,pl: 'To tylko przybliżona ocena, która może być bardzo niedokładna i nie może zastąpić faktycznego poziomu cukru we krwi. Zastosowano formułę:' ,tr: 'Bu bir kaba tahmindir ve çok hata içerebilir gerçek kan şekeri testlerinin yerini tutmayacaktır. Kullanılan formülde buradandır:' + ,hu: 'Ez egy nagyon durva számítás ami nem pontos és nem helyettesíti a cukorszint mérését. A képlet a következő helyről lett véve:' } , 'Filter by hours' : { cs: ' Filtr podle hodin' @@ -12912,6 +13456,7 @@ function init() { ,hr: 'Filter po satima' ,pl: 'Filtruj po godzinach' ,tr: 'Saatlere göre filtrele' + ,hu: 'Megszűrni órák alapján' } , 'Time in fluctuation and Time in rapid fluctuation measure the % of time during the examined period, during which the blood glucose has been changing relatively fast or rapidly. Lower values are better.' : { cs: 'Doba měnící se glykémie a rapidně se měnící glykémie měří % času ve zkoumaném období, během kterého se glykémie měnila relativně rychle nebo rapidně. Nižší hodnota je lepší.' @@ -12931,6 +13476,7 @@ function init() { ,hr: 'Vrijeme u fluktuaciji i vrijeme u brzoj fluktuaciji mjere % vremena u gledanom periodu, tijekom kojeg se GUK mijenja relativno brzo ili brzo. Niže vrijednosti su bolje.' ,pl: 'Czas fluktuacji i szybki czas fluktuacji mierzą % czasu w badanym okresie, w którym poziom glukozy we krwi zmieniał się szybko lub bardzo szybko. Preferowane są wolniejsze zmiany' ,tr: 'Dalgalanmadaki zaman ve Hızlı dalgalanmadaki zaman, kan şekerinin nispeten hızlı veya çok hızlı bir şekilde değiştiği, incelenen dönemdeki zamanın %\'sini ölçer. Düşük değerler daha iyidir.' + ,hu: 'A sima és magas kilengésnél mért idő százalékban kifelyezve, ahol a cukorszint aránylag nagyokat változott. A kisebb értékek jobbak ebben az esetben' } , 'Mean Total Daily Change is a sum of the absolute value of all glucose excursions for the examined period, divided by the number of days. Lower is better.' : { cs: 'Průměrná celková denní změna je součet absolutních hodnoty všech glykémií za sledované období, děleno počtem dní. Nižší hodnota je lepší.' @@ -12950,6 +13496,7 @@ function init() { ,hr: 'Srednja ukupna dnevna promjena je suma apsolutnih vrijednosti svih pomaka u gledanom periodu, podijeljeno s brojem dana. Niže vrijednosti su bolje.' ,pl: 'Sednia całkowita dziennych zmian jest sumą wszystkich zmian glikemii w badanym okresie, podzielonym przez liczbę dni. Mniejsze są lepsze' ,tr: 'Toplam Günlük Değişim, incelenen süre için, gün sayısına bölünen tüm glukoz değerlerinin mutlak değerinin toplamıdır. Düşük değer daha iyidir.' + ,hu: 'Az átlagos napi változás az abszolút értékek összege elosztva a napok számával. A kisebb érték jobb ebben az esetben.' } , 'Mean Hourly Change is a sum of the absolute value of all glucose excursions for the examined period, divided by the number of hours in the period. Lower is better.' : { cs: 'Průměrná hodinová změna je součet absolutní hodnoty všech glykémií za sledované období, dělených počtem hodin v daném období. Nižší hodnota je lepší.' @@ -12969,6 +13516,7 @@ function init() { ,hr: 'Srednja ukupna promjena po satu je suma apsolutnih vrijednosti svih pomaka u gledanom periodu, podijeljeno s brojem sati. Niže vrijednosti su bolje.' ,pl: 'Sednia całkowita godzinnych zmian jest sumą wszystkich zmian glikemii w badanym okresie, podzielonym przez liczbę godzin. Mniejsze są lepsze' ,tr: 'Saat başına ortalama değişim, gözlem periyodu üzerindeki tüm glikoz değişikliklerinin mutlak değerlerinin saat sayısına bölünmesiyle elde edilen toplam değerdir. Düşük değerler daha iyidir.' + ,hu: 'Az átlagos óránkénti változás az abszút értékek összege elosztva a napok számával. A kisebb érték jobb ebben az esetben.' } , 'GVI (Glycemic Variability Index) and PGS (Patient Glycemic Status) are measures developed by Dexcom, detailed can be found here.' : { cs: '">zde.' @@ -13009,6 +13558,7 @@ function init() { ,hr: '">ovdje.' ,pl: '">tutaj.' ,tr: '">buradan.' + ,hu: '">itt találhatóak.' } , 'Mean Total Daily Change' : { cs: 'Průměrná celková denní změna' @@ -13029,6 +13579,7 @@ function init() { ,hr: 'Srednja ukupna dnevna promjena' ,pl: 'Średnia całkowita dziennych zmian' ,tr: 'Günde toplam ortalama değişim' + ,hu: 'Áltagos napi változás' } , 'Mean Hourly Change' : { cs: 'Průměrná hodinová změna' @@ -13049,6 +13600,7 @@ function init() { ,hr: 'Srednja ukupna promjena po satu' ,pl: 'Średnia całkowita godzinnych zmian' ,tr: 'Saatte ortalama değişim' + ,hu: 'Átlagos óránkénti változás' } , 'FortyFiveDown': { bg: 'slightly dropping' @@ -13075,6 +13627,7 @@ function init() { , tr: 'biraz düşen' , zh_cn: '缓慢下降' , zh_tw: 'slightly dropping' + , hu: 'lassan csökken' }, 'FortyFiveUp': { @@ -13102,6 +13655,7 @@ function init() { , tr: 'biraz yükselen' , zh_cn: '缓慢上升' , zh_tw: 'slightly rising' + , hu: 'lassan növekszik' }, 'Flat': { bg: 'holding' @@ -13128,6 +13682,7 @@ function init() { , tr: 'sabit' , zh_cn: '平' , zh_tw: 'holding' + , hu: 'stabil' }, 'SingleUp': { bg: 'rising' @@ -13154,6 +13709,7 @@ function init() { , tr: 'yükseliyor' , zh_cn: '上升' , zh_tw: 'rising' + , hu: 'emelkedik' }, 'SingleDown': { bg: 'dropping' @@ -13180,6 +13736,7 @@ function init() { , tr: 'düşüyor' , zh_cn: '下降' , zh_tw: 'dropping' + , hu: 'csökken' }, 'DoubleDown': { bg: 'rapidly dropping' @@ -13206,6 +13763,7 @@ function init() { , tr: 'hızlı düşen' , zh_cn: '快速下降' , zh_tw: 'rapidly dropping' + , hu: 'gyorsan csökken' }, 'DoubleUp': { bg: 'rapidly rising' @@ -13232,6 +13790,7 @@ function init() { , tr: 'hızla yükselen' , zh_cn: '快速上升' , zh_tw: 'rapidly rising' + , hu: 'gyorsan emelkedik' }, 'virtAsstUnknown': { bg: 'That value is unknown at the moment. Please see your Nightscout site for more details.' @@ -13258,6 +13817,7 @@ function init() { , tr: 'That value is unknown at the moment. Please see your Nightscout site for more details.' , zh_cn: 'That value is unknown at the moment. Please see your Nightscout site for more details.' , zh_tw: 'That value is unknown at the moment. Please see your Nightscout site for more details.' + , hu: 'Az adat ismeretlen. Kérem nézd meg a Nightscout oldalt részletekért' }, 'virtAsstTitleAR2Forecast': { bg: 'AR2 Forecast' @@ -13284,6 +13844,7 @@ function init() { , tr: 'AR2 Forecast' , zh_cn: 'AR2 Forecast' , zh_tw: 'AR2 Forecast' + , hu: 'AR2 Előrejelzés' }, 'virtAsstTitleCurrentBasal': { bg: 'Current Basal' @@ -13310,6 +13871,7 @@ function init() { , tr: 'Current Basal' , zh_cn: 'Current Basal' , zh_tw: 'Current Basal' + , hu: 'Jelenlegi Bazál' }, 'virtAsstTitleCurrentCOB': { bg: 'Current COB' @@ -13336,6 +13898,7 @@ function init() { , tr: 'Current COB' , zh_cn: 'Current COB' , zh_tw: 'Current COB' + , hu: 'Jelenlegi COB' }, 'virtAsstTitleCurrentIOB': { bg: 'Current IOB' @@ -13362,6 +13925,7 @@ function init() { , tr: 'Current IOB' , zh_cn: 'Current IOB' , zh_tw: 'Current IOB' + , hu: 'Jelenlegi IOB' }, 'virtAsstTitleLaunch': { bg: 'Welcome to Nightscout' @@ -13388,6 +13952,7 @@ function init() { , tr: 'Welcome to Nightscout' , zh_cn: 'Welcome to Nightscout' , zh_tw: 'Welcome to Nightscout' + , hu: 'Üdvözöllek a Nightscouton' }, 'virtAsstTitleLoopForecast': { bg: 'Loop Forecast' @@ -13414,6 +13979,7 @@ function init() { , tr: 'Loop Forecast' , zh_cn: 'Loop Forecast' , zh_tw: 'Loop Forecast' + , hu: 'Loop Előrejelzés' }, 'virtAsstTitleLastLoop': { bg: 'Last Loop' @@ -13440,6 +14006,7 @@ function init() { , tr: 'Last Loop' , zh_cn: 'Last Loop' , zh_tw: 'Last Loop' + , hu: 'Utolsó Loop' }, 'virtAsstTitleOpenAPSForecast': { bg: 'OpenAPS Forecast' @@ -13466,6 +14033,7 @@ function init() { , tr: 'OpenAPS Forecast' , zh_cn: 'OpenAPS Forecast' , zh_tw: 'OpenAPS Forecast' + , hu: 'OpenAPS Előrejelzés' }, 'virtAsstTitlePumpReservoir': { bg: 'Insulin Remaining' @@ -13492,6 +14060,7 @@ function init() { , tr: 'Insulin Remaining' , zh_cn: 'Insulin Remaining' , zh_tw: 'Insulin Remaining' + , hu: 'Fennmaradó inzulin' }, 'virtAsstTitlePumpBattery': { bg: 'Pump Battery' @@ -13518,6 +14087,7 @@ function init() { , tr: 'Pump Battery' , zh_cn: 'Pump Battery' , zh_tw: 'Pump Battery' + , hu: 'Pumpa töltöttsége' }, 'virtAsstTitleRawBG': { bg: 'Current Raw BG' @@ -13544,6 +14114,7 @@ function init() { , tr: 'Current Raw BG' , zh_cn: 'Current Raw BG' , zh_tw: 'Current Raw BG' + , hu: 'Jelenlegi nyers cukorszint' }, 'virtAsstTitleUploaderBattery': { bg: 'Uploader Battery' @@ -13569,7 +14140,8 @@ function init() { , sv: 'Uploader Battery' , tr: 'Uploader Battery' , zh_cn: 'Uploader Battery' - , zh_tw: 'Uploader Battery' + , zh_tw: 'Current Raw BG' + , hu: 'Feltöltő töltöttsége' }, 'virtAsstTitleCurrentBG': { bg: 'Current BG' @@ -13596,6 +14168,7 @@ function init() { , tr: 'Current BG' , zh_cn: 'Current BG' , zh_tw: 'Current BG' + , hu: 'Jelenlegi Cukorszint' }, 'virtAsstTitleFullStatus': { bg: 'Full Status' @@ -13622,6 +14195,7 @@ function init() { , tr: 'Full Status' , zh_cn: 'Full Status' , zh_tw: 'Full Status' + , hu: 'Teljes Státusz' }, 'virtAsstTitleCGMMode': { bg: 'CGM Mode' @@ -13648,6 +14222,7 @@ function init() { , tr: 'CGM Mode' , zh_cn: 'CGM Mode' , zh_tw: 'CGM Mode' + , hu: 'CGM Mód' }, 'virtAsstTitleCGMStatus': { bg: 'CGM Status' @@ -13674,6 +14249,7 @@ function init() { , tr: 'CGM Status' , zh_cn: 'CGM Status' , zh_tw: 'CGM Status' + , hu: 'CGM Státusz' }, 'virtAsstTitleCGMSessionAge': { bg: 'CGM Session Age' @@ -13700,6 +14276,7 @@ function init() { , tr: 'CGM Session Age' , zh_cn: 'CGM Session Age' , zh_tw: 'CGM Session Age' + , hu: 'CGM életkora' }, 'virtAsstTitleCGMTxStatus': { bg: 'CGM Transmitter Status' @@ -13726,6 +14303,7 @@ function init() { , tr: 'CGM Transmitter Status' , zh_cn: 'CGM Transmitter Status' , zh_tw: 'CGM Transmitter Status' + , hu: 'CGM kapcsolat státusza' }, 'virtAsstTitleCGMTxAge': { bg: 'CGM Transmitter Age' @@ -13778,6 +14356,7 @@ function init() { , tr: 'CGM Noise' , zh_cn: 'CGM Noise' , zh_tw: 'CGM Noise' + , hu: 'CGM Zaj' }, 'virtAsstTitleDelta': { bg: 'Blood Glucose Delta' @@ -13804,6 +14383,7 @@ function init() { , tr: 'Blood Glucose Delta' , zh_cn: 'Blood Glucose Delta' , zh_tw: 'Blood Glucose Delta' + , hu: 'Csukoszint delta' }, 'virtAsstStatus': { bg: '%1 and %2 as of %3.' @@ -13830,6 +14410,7 @@ function init() { , tr: '%1 ve %2 e kadar %3.' , zh_cn: '%1 和 %2 到 %3.' , zh_tw: '%1 and %2 as of %3.' + , hu: '%1 es %2 %3-tól.' }, 'virtAsstBasal': { bg: '%1 současný bazál je %2 jednotek za hodinu' @@ -13856,6 +14437,7 @@ function init() { , tr: '%1 geçerli bazal oranı saatte %2 ünite' , zh_cn: '%1 当前基础率是 %2 U/小时' , zh_tw: '%1 current basal is %2 units per hour' + , hu: '%1 a jelenlegi bazál %2 egység óránként' }, 'virtAsstBasalTemp': { bg: '%1 dočasný bazál %2 jednotek za hodinu skončí %3' @@ -13882,6 +14464,7 @@ function init() { , tr: '%1 geçici bazal %2 ünite %3 sona eriyor' , zh_cn: '%1 临时基础率 %2 U/小时将会在 %3结束' , zh_tw: '%1 temp basal of %2 units per hour will end %3' + , hu: '%1 átmeneti bazál %2 egység óránként ami %3 -kor jár le' }, 'virtAsstIob': { bg: 'a máte %1 jednotek aktivního inzulínu.' @@ -13908,6 +14491,7 @@ function init() { , tr: 've Sizde %1 aktif insulin var' , zh_cn: '并且你有 %1 的活性胰岛素.' , zh_tw: 'and you have %1 insulin on board.' + , hu: 'és neked %1 inzulin van a testedben.' }, 'virtAsstIobIntent': { bg: 'Máte %1 jednotek aktivního inzulínu' @@ -13934,6 +14518,7 @@ function init() { , tr: 'Sizde %1 aktif insülin var' , zh_cn: '你有 %1 的活性胰岛素' , zh_tw: 'You have %1 insulin on board' + , hu: 'Neked %1 inzulin van a testedben' }, 'virtAsstIobUnits': { bg: '%1 units of' @@ -13960,6 +14545,7 @@ function init() { , tr: 'hala %1 birim' , zh_cn: '%1 单位' , zh_tw: '%1 units of' + , hu: '%1 egység' }, 'virtAsstLaunch': { bg: 'What would you like to check on Nightscout?' @@ -13986,6 +14572,7 @@ function init() { , tr: 'What would you like to check on Nightscout?' , zh_cn: 'What would you like to check on Nightscout?' , zh_tw: 'What would you like to check on Nightscout?' + , hu: 'Mit szeretnél ellenőrizni a Nightscout oldalon?' }, 'virtAsstPreamble': { bg: 'Your' @@ -14012,6 +14599,7 @@ function init() { , tr: 'Senin' , zh_cn: '你的' , zh_tw: 'Your' + , hu: 'A tied' }, 'virtAsstPreamble3person': { bg: '%1 has a ' @@ -14038,6 +14626,7 @@ function init() { , tr: '%1 bir tane var' , zh_cn: '%1 有一个 ' , zh_tw: '%1 has a ' + , hu: '%1 -nak van ' }, 'virtAsstNoInsulin': { bg: 'no' @@ -14064,6 +14653,7 @@ function init() { , tr: 'yok' , zh_cn: '否' , zh_tw: 'no' + , hu: 'semmilyen' }, 'virtAsstUploadBattery': { bg: 'Your uploader battery is at %1' @@ -14081,6 +14671,7 @@ function init() { , pl: 'Twoja bateria ma %1' , ru: 'батарея загрузчика %1' , tr: 'Yükleyici piliniz %1' + , hu: 'A felöltőd töltöttsége %1' }, 'virtAsstReservoir': { bg: 'You have %1 units remaining' @@ -14098,6 +14689,7 @@ function init() { , pl: 'W zbiorniku pozostało %1 jednostek' , ru: 'остается %1 ед' , tr: '%1 birim kaldı' + , hu: '%1 egység maradt hátra' }, 'virtAsstPumpBattery': { bg: 'Your pump battery is at %1 %2' @@ -14115,6 +14707,7 @@ function init() { , pl: 'Bateria pompy jest w %1 %2' , ru: 'батарея помпы %1 %2' , tr: 'Pompa piliniz %1 %2' + , hu: 'A pumpád töltöttsége %1 %2' }, 'virtAsstUploaderBattery': { bg: 'Your uploader battery is at %1' @@ -14132,6 +14725,7 @@ function init() { , pl: 'Your uploader battery is at %1' , ru: 'Батарея загрузчика %1' , tr: 'Your uploader battery is at %1' + , hu: 'A feltöltőd töltöttsége %1' }, 'virtAsstLastLoop': { bg: 'The last successful loop was %1' @@ -14149,6 +14743,7 @@ function init() { , pl: 'Ostatnia pomyślna pętla była %1' , ru: 'недавний успешный цикл был %1' , tr: 'Son başarılı döngü %1 oldu' + , hu: 'Az utolsó sikeres loop %1-kor volt' }, 'virtAsstLoopNotAvailable': { bg: 'Loop plugin does not seem to be enabled' @@ -14166,6 +14761,7 @@ function init() { , pl: 'Plugin Loop prawdopodobnie nie jest włączona' , ru: 'Расширение ЗЦ Loop не активировано' , tr: 'Döngü eklentisi etkin görünmüyor' + , hu: 'A loop kiegészítés valószínűleg nincs bekapcsolva' }, 'virtAsstLoopForecastAround': { bg: 'According to the loop forecast you are expected to be around %1 over the next %2' @@ -14183,6 +14779,7 @@ function init() { , pl: 'Zgodnie z prognozą pętli, glikemia around %1 będzie podczas następnego %2' , ru: 'по прогнозу алгоритма ЗЦ ожидается около %1 за последующие %2' , tr: 'Döngü tahminine göre sonraki %2 ye göre around %1 olması bekleniyor' + , hu: 'A loop előrejelzése alapján a követlező %2 időszakban körülbelül %1 lesz' }, 'virtAsstLoopForecastBetween': { bg: 'According to the loop forecast you are expected to be between %1 and %2 over the next %3' @@ -14200,6 +14797,7 @@ function init() { , pl: 'Zgodnie z prognozą pętli, glikemia between %1 and %2 będzie podczas następnego %3' , ru: 'по прогнозу алгоритма ЗЦ ожидается между %1 и %2 за последующие %3' , tr: 'Döngü tahminine göre sonraki %3 ye göre between %1 and %2 olması bekleniyor' + , hu: 'A loop előrejelzése alapján a követlező %3 időszakban %1 és %2 között leszel' }, 'virtAsstAR2ForecastAround': { bg: 'According to the AR2 forecast you are expected to be around %1 over the next %2' @@ -14217,6 +14815,7 @@ function init() { , pl: 'According to the AR2 forecast you are expected to be around %1 over the next %2' , ru: 'По прогнозу AR2 ожидается около %1 в следующие %2' , tr: 'According to the AR2 forecast you are expected to be around %1 over the next %2' + , hu: 'Az AR2ües előrejelzés alapján a követlező %2 időszakban körülbelül %1 lesz' }, 'virtAsstAR2ForecastBetween': { bg: 'According to the AR2 forecast you are expected to be between %1 and %2 over the next %3' @@ -14234,6 +14833,7 @@ function init() { , pl: 'According to the AR2 forecast you are expected to be between %1 and %2 over the next %3' , ru: 'По прогнозу AR2 ожидается между %1 и %2 в следующие %3' , tr: 'According to the AR2 forecast you are expected to be between %1 and %2 over the next %3' + , hu: 'Az AR2 előrejelzése alapján a követlező %3 időszakban %1 és %2 között leszel' }, 'virtAsstForecastUnavailable': { bg: 'Unable to forecast with the data that is available' @@ -14251,6 +14851,7 @@ function init() { , pl: 'Prognoza pętli nie jest możliwa, z dostępnymi danymi.' , ru: 'прогноз при таких данных невозможен' , tr: 'Mevcut verilerle tahmin edilemedi' + , hu: 'Nem tudok előrejelzést készíteni hiányos adatokból' }, 'virtAsstRawBG': { en: 'Your raw bg is %1' @@ -14268,6 +14869,7 @@ function init() { , pl: 'Glikemia RAW wynosi %1' , ru: 'ваши необработанные данные RAW %1' , tr: 'Ham kan şekeriniz %1' + , hu: 'A nyers cukorszinted %1' }, 'virtAsstOpenAPSForecast': { en: 'The OpenAPS Eventual BG is %1' @@ -14285,6 +14887,7 @@ function init() { , pl: 'Glikemia prognozowana przez OpenAPS wynosi %1' , ru: 'OpenAPS прогнозирует ваш СК как %1 ' , tr: 'OpenAPS tarafından tahmin edilen kan şekeri %1' + , hu: 'Az OpenAPS cukorszinted %1' }, 'virtAsstCob3person': { bg: '%1 has %2 carbohydrates on board' @@ -14311,6 +14914,7 @@ function init() { , tr: '%1 has %2 carbohydrates on board' , zh_cn: '%1 has %2 carbohydrates on board' , zh_tw: '%1 has %2 carbohydrates on board' + , hu: '%1 -nak %2 szénhodrátja van a testében' }, 'virtAsstCob': { bg: 'You have %1 carbohydrates on board' @@ -14337,6 +14941,7 @@ function init() { , tr: 'You have %1 carbohydrates on board' , zh_cn: 'You have %1 carbohydrates on board' , zh_tw: 'You have %1 carbohydrates on board' + , hu: 'Neked %1 szénhidrát van a testedben' }, 'virtAsstCGMMode': { bg: 'Your CGM mode was %1 as of %2.' @@ -14363,6 +14968,7 @@ function init() { , tr: 'Your CGM mode was %1 as of %2.' , zh_cn: 'Your CGM mode was %1 as of %2.' , zh_tw: 'Your CGM mode was %1 as of %2.' + , hu: 'A CGM módod %1 volt %2 -kor.' }, 'virtAsstCGMStatus': { bg: 'Your CGM status was %1 as of %2.' @@ -14389,6 +14995,7 @@ function init() { , tr: 'Your CGM status was %1 as of %2.' , zh_cn: 'Your CGM status was %1 as of %2.' , zh_tw: 'Your CGM status was %1 as of %2.' + , hu: 'A CGM státuszod %1 volt %2 -kor.' }, 'virtAsstCGMSessAge': { bg: 'Your CGM session has been active for %1 days and %2 hours.' @@ -14415,6 +15022,7 @@ function init() { , tr: 'Your CGM session has been active for %1 days and %2 hours.' , zh_cn: 'Your CGM session has been active for %1 days and %2 hours.' , zh_tw: 'Your CGM session has been active for %1 days and %2 hours.' + , hu: 'A CGM kapcsolatod %1 napja és %2 órája aktív' }, 'virtAsstCGMSessNotStarted': { bg: 'There is no active CGM session at the moment.' @@ -14441,6 +15049,7 @@ function init() { , tr: 'There is no active CGM session at the moment.' , zh_cn: 'There is no active CGM session at the moment.' , zh_tw: 'There is no active CGM session at the moment.' + , hu: 'Jelenleg nincs aktív CGM kapcsolatod' }, 'virtAsstCGMTxStatus': { bg: 'Your CGM transmitter status was %1 as of %2.' @@ -14467,6 +15076,7 @@ function init() { , tr: 'Your CGM transmitter status was %1 as of %2.' , zh_cn: 'Your CGM transmitter status was %1 as of %2.' , zh_tw: 'Your CGM transmitter status was %1 as of %2.' + , hu: 'A CGM jeladód státusza %1 volt %2-kor' }, 'virtAsstCGMTxAge': { bg: 'Your CGM transmitter is %1 days old.' @@ -14493,6 +15103,7 @@ function init() { , tr: 'Your CGM transmitter is %1 days old.' , zh_cn: 'Your CGM transmitter is %1 days old.' , zh_tw: 'Your CGM transmitter is %1 days old.' + , hu: 'A CGM jeladód %1 napos.' }, 'virtAsstCGMNoise': { bg: 'Your CGM noise was %1 as of %2.' @@ -14519,6 +15130,7 @@ function init() { , tr: 'Your CGM noise was %1 as of %2.' , zh_cn: 'Your CGM noise was %1 as of %2.' , zh_tw: 'Your CGM noise was %1 as of %2.' + , hu: 'A CGM jeladó zaja %1 volt %2-kor' }, 'virtAsstCGMBattOne': { bg: 'Your CGM battery was %1 volts as of %2.' @@ -14545,6 +15157,7 @@ function init() { , tr: 'Your CGM battery was %1 volts as of %2.' , zh_cn: 'Your CGM battery was %1 volts as of %2.' , zh_tw: 'Your CGM battery was %1 volts as of %2.' + , hu: 'A CGM töltöttsége %1 VOLT volt %2-kor' }, 'virtAsstCGMBattTwo': { bg: 'Your CGM battery levels were %1 volts and %2 volts as of %3.' @@ -14571,6 +15184,7 @@ function init() { , tr: 'Your CGM battery levels were %1 volts and %2 volts as of %3.' , zh_cn: 'Your CGM battery levels were %1 volts and %2 volts as of %3.' , zh_tw: 'Your CGM battery levels were %1 volts and %2 volts as of %3.' + , hu: 'A CGM töltöttsége %1 és %2 VOLT volt %3-kor' }, 'virtAsstDelta': { bg: 'Your delta was %1 between %2 and %3.' @@ -14597,6 +15211,7 @@ function init() { , tr: 'Your delta was %1 between %2 and %3.' , zh_cn: 'Your delta was %1 between %2 and %3.' , zh_tw: 'Your delta was %1 between %2 and %3.' + , hu: 'A deltád %1 volt %2 és %3 között' }, 'virtAsstUnknownIntentTitle': { en: 'Unknown Intent' @@ -14613,7 +15228,7 @@ function init() { , hr: 'Unknown Intent' , pl: 'Unknown Intent' , ru: 'Неизвестное намерение' - , tr: 'Unknown Intent' + , tr: 'Ismeretlen szándék' }, 'virtAsstUnknownIntentText': { en: 'I\'m sorry, I don\'t know what you\'re asking for.' @@ -14631,6 +15246,7 @@ function init() { , pl: 'I\'m sorry, I don\'t know what you\'re asking for.' , ru: 'Ваш запрос непонятен' , tr: 'I\'m sorry, I don\'t know what you\'re asking for.' + , hu: 'Sajnálom, nem tudom mit szeretnél tőlem.' }, 'Fat [g]': { cs: 'Tuk [g]' @@ -14651,6 +15267,7 @@ function init() { ,pl: 'Tłuszcz [g]' ,tr: 'Yağ [g]' ,he: '[g] שמן' + ,hu: 'Zsír [g]' }, 'Protein [g]': { cs: 'Proteiny [g]' @@ -14671,6 +15288,7 @@ function init() { ,pl: 'Białko [g]' ,tr: 'Protein [g]' ,he: '[g] חלבון' + ,hu: 'Protein [g]' }, 'Energy [kJ]': { cs: 'Energie [kJ]' @@ -14691,6 +15309,7 @@ function init() { ,pl: 'Energia [kJ}' ,tr: 'Enerji [kJ]' ,he: '[kJ] אנרגיה' + ,hu: 'Energia [kJ]' }, 'Clock Views:': { cs: 'Hodiny:' @@ -14711,6 +15330,7 @@ function init() { ,pl: 'Widoki zegarów' ,tr: 'Saat Görünümü' ,he: 'צגים השעון' + ,hu: 'Óra:' }, 'Clock': { cs: 'Hodiny' @@ -14730,6 +15350,7 @@ function init() { ,ru: 'часы' ,tr: 'Saat' ,he: 'שעון' + ,hu: 'Óra:' }, 'Color': { cs: 'Barva' @@ -14749,6 +15370,7 @@ function init() { ,ru: 'цвет' ,tr: 'Renk' ,he: 'צבע' + ,hu: 'Szinek' }, 'Simple': { cs: 'Jednoduchý' @@ -14768,6 +15390,7 @@ function init() { ,ru: 'простой' ,tr: 'Basit' ,he: 'פשוט' + ,hu: 'Csak cukor' }, 'TDD average': { cs: 'Průměrná denní dávka' @@ -14785,6 +15408,7 @@ function init() { , pl: 'Średnia dawka dzienna' , ru: 'средняя суточная доза инсулина' , tr: 'Ortalama günlük Toplam Doz (TDD)' + , hu: 'Átlagos napi adag (TDD)' }, 'Carbs average': { cs: 'Průměrné množství sacharidů' @@ -14802,7 +15426,8 @@ function init() { , pl: 'Średnia ilość węglowodanów' , ru: 'среднее кол-во углеводов за сутки' , tr: 'Günde ortalama karbonhidrat' - ,he: 'פחמימות ממוצע' + , he: 'פחמימות ממוצע' + , hu: 'Szenhidrát átlag' }, 'Eating Soon': { cs: 'Blížící se jídlo' @@ -14821,6 +15446,7 @@ function init() { , ru: 'Ожидаемый прием пищи' , tr: 'Yakında Yenecek' , he: 'אוכל בקרוב' + , hu: 'Hamarosan evés' }, 'Last entry {0} minutes ago': { cs: 'Poslední hodnota {0} minut zpět' @@ -14838,6 +15464,7 @@ function init() { , pl: 'Ostatni wpis przed {0} minutami' , ru: 'предыдущая запись {0} минут назад' , tr: 'Son giriş {0} dakika önce' + , hu: 'Utolsó bejegyzés {0} volt' }, 'change': { cs: 'změna' @@ -14856,6 +15483,7 @@ function init() { , ru: 'замена' , tr: 'değişiklik' , he: 'שינוי' + , hu: 'változás' }, 'Speech': { cs: 'Hlas' @@ -14874,6 +15502,7 @@ function init() { , ru: 'речь' , tr: 'Konuş' , he: 'דיבור' + , hu: 'Beszéd' }, 'Target Top': { cs: 'Horní cíl' @@ -14892,6 +15521,7 @@ function init() { , de: 'Oberes Ziel' , tr: 'Hedef Üst' , he: 'ראש היעד' + , hu: 'Felsó cél' }, 'Target Bottom': { cs: 'Dolní cíl' @@ -14910,6 +15540,7 @@ function init() { , de: 'Unteres Ziel' , tr: 'Hedef Alt' , he: 'תחתית היעד' + , hu: 'Alsó cél' }, 'Canceled': { cs: 'Zrušený' @@ -14928,6 +15559,7 @@ function init() { , de: 'Abgebrochen' , tr: 'İptal edildi' , he: 'מבוטל' + , hu: 'Megszüntetett' }, 'Meter BG': { cs: 'Hodnota z glukoměru' @@ -14946,6 +15578,7 @@ function init() { , de: 'Wert Blutzuckermessgerät' , tr: 'Glikometre KŞ' , he: 'סוכר הדם של מד' + , hu: 'Cukorszint a mérőből' }, 'predicted': { cs: 'přepověď' @@ -14964,6 +15597,7 @@ function init() { , de: 'vorhergesagt' , tr: 'tahmin' , he: 'חזה' + , hu: 'előrejelzés' }, 'future': { cs: 'budoucnost' @@ -14982,6 +15616,7 @@ function init() { , de: 'Zukunft' , tr: 'gelecek' , he: 'עתיד' + , hu: 'jövő' }, 'ago': { cs: 'zpět' @@ -14999,6 +15634,7 @@ function init() { , de: 'vor' , tr: 'önce' , he: 'לפני' + , hu: 'ezelött' }, 'Last data received': { cs: 'Poslední data přiajata' @@ -15017,6 +15653,7 @@ function init() { , de: 'Zuletzt Daten empfangen' , tr: 'Son veri alındı' , he: 'הנתונים המקבל אחרונים' + , hu: 'Utólsó adatok fogadva' }, 'Clock View': { cs: 'Hodiny' @@ -15037,6 +15674,7 @@ function init() { ,pl: 'Widok zegara' ,tr: 'Saat Görünümü' ,he: 'צג השעון' + ,hu: 'Idő' }, 'Protein': { fi: 'Proteiini' @@ -15047,6 +15685,7 @@ function init() { ,ru: 'Белки' ,he: 'חלבון' ,nl: 'Eiwit' + ,hu: 'Protein' }, 'Fat': { fi: 'Rasva' @@ -15057,6 +15696,7 @@ function init() { ,ru: 'Жиры' ,he: 'שמן' ,nl: 'Vet' + ,hu: 'Zsír' }, 'Protein average': { fi: 'Proteiini keskiarvo' @@ -15067,6 +15707,7 @@ function init() { ,ru: 'Средний белок' ,he: 'חלבון ממוצע' ,nl: 'eiwitgemiddelde' + ,hu: 'Protein átlag' }, 'Fat average': { fi: 'Rasva keskiarvo' @@ -15077,6 +15718,7 @@ function init() { ,ru: 'Средний жир' ,he: 'שמן ממוצע' ,nl: 'Vetgemiddelde' + ,hu: 'Zsír átlag' }, 'Total carbs': { fi: 'Hiilihydraatit yhteensä' @@ -15087,6 +15729,7 @@ function init() { ,ru: 'Всего углеводов' ,he: 'כל פחמימות' ,nl: 'Totaal koolhydraten' + ,hu: 'Összes szénhidrát' }, 'Total protein': { fi: 'Proteiini yhteensä' @@ -15097,6 +15740,7 @@ function init() { ,ru: 'Всего белков' ,he: 'כל חלבונים' ,nl: 'Totaal eiwitten' + ,hu: 'Összes protein' }, 'Total fat': { fi: 'Rasva yhteensä' @@ -15107,40 +15751,57 @@ function init() { ,ru: 'Всего жиров' ,he: 'כל שומנים' ,nl: 'Totaal vetten' + ,hu: 'Összes zsír' }, 'Database Size': { pl: 'Rozmiar Bazy Danych' ,nl: 'Grootte database' + ,de: 'Datenbankgröße' + ,hu: 'Adatbázis mérete' }, 'Database Size near its limits!': { pl: 'Rozmiar bazy danych zbliża się do limitu!' ,nl: 'Database grootte nadert limiet!' + ,de: 'Datenbank fast voll!' + ,hu: 'Az adatbázis majdnem megtelt!' }, 'Database size is %1 MiB out of %2 MiB. Please backup and clean up database!': { pl: 'Baza danych zajmuje %1 MiB z dozwolonych %2 MiB. Proszę zrób kopię zapasową i oczyść bazę danych!' ,nl: 'Database grootte is %1 MiB van de %2 MiB. Maak een backup en verwijder oude data' + ,de: 'Die Datenbankgröße beträgt %1 MiB von %2 MiB. Bitte sichere deine Daten und bereinige die Datenbank!' + ,hu: 'Az adatbázis mérete %1 MiB a rendelkezésre álló %2 MiB-ból. Készítsen biztonsági másolatot!' }, 'Database file size': { pl: 'Rozmiar pliku bazy danych' ,nl: 'Database bestandsgrootte' + ,de: 'Datenbank-Dateigröße' + ,hu: 'Adatbázis file mérete' }, '%1 MiB of %2 MiB (%3%)': { pl: '%1 MiB z %2 MiB (%3%)' ,nl: '%1 MiB van de %2 MiB (%3%)' + ,de: '%1 MiB von %2 MiB (%3%)' + ,hu: '%1 MiB %2 MiB-ból (%3%)' }, 'Data size': { pl: 'Rozmiar danych' ,nl: 'Datagrootte' + ,de: 'Datengröße' + ,hu: 'Adatok mérete' }, 'virtAsstDatabaseSize': { - en: '%1 MiB that is %2% of available database space' + en: '%1 MiB. That is %2% of available database space.' ,pl: '%1 MiB co stanowi %2% przestrzeni dostępnej dla bazy danych' ,nl: '%1 MiB dat is %2% van de beschikbaare database ruimte' + ,de: '%1 MiB. Das sind %2% des verfügbaren Datenbank-Speicherplatzes.' + ,hu: '%1 MiB ami %2% a rendelkezésre álló méretből' }, 'virtAsstTitleDatabaseSize': { en: 'Database file size' ,pl: 'Rozmiar pliku bazy danych' ,nl: 'Database bestandsgrootte' + ,de: 'Datenbank-Dateigröße' + ,hu: 'Adatbázis file méret' } }; diff --git a/lib/plugins/ar2.js b/lib/plugins/ar2.js index 133c5b8d3c9..5232feb0245 100644 --- a/lib/plugins/ar2.js +++ b/lib/plugins/ar2.js @@ -67,8 +67,8 @@ function init (ctx) { var prop = sbx.properties.ar2; - if (prop) { - sbx.notifications.requestNotify({ + if (prop && prop.level) { + const notify = { level: prop.level , title: buildTitle(prop, sbx) , message: sbx.buildDefaultMessage() @@ -76,7 +76,8 @@ function init (ctx) { , pushoverSound: pushoverSound(prop, sbx.levels) , plugin: ar2 , debug: buildDebug(prop, sbx) - }); + }; + sbx.notifications.requestNotify(notify); } }; @@ -147,8 +148,9 @@ function init (ctx) { }; function virtAsstAr2Handler (next, slots, sbx) { - if (sbx.properties.ar2.forecast.predicted) { - var forecast = sbx.properties.ar2.forecast.predicted; + var predicted = _.get(sbx, 'properties.ar2.forecast.predicted'); + if (predicted) { + var forecast = predicted; var max = forecast[0].mgdl; var min = forecast[0].mgdl; var maxForecastMills = forecast[0].mills; @@ -223,9 +225,9 @@ function selectEventType (prop, sbx) { var eventName = ''; if (in20mins !== undefined) { - if (in20mins > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) { + if (sbx.settings.alarmHigh && in20mins > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) { eventName = 'high'; - } else if (in20mins < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) { + } else if (sbx.settings.alarmLow && in20mins < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) { eventName = 'low'; } } diff --git a/lib/plugins/basalprofile.js b/lib/plugins/basalprofile.js index 4347a7005ec..806dde5859d 100644 --- a/lib/plugins/basalprofile.js +++ b/lib/plugins/basalprofile.js @@ -2,6 +2,7 @@ var times = require('../times'); var moment = require('moment'); var consts = require('../constants'); +var _ = require('lodash'); function init (ctx) { @@ -114,13 +115,13 @@ function init (ctx) { function basalMessage(slots, sbx) { var basalValue = sbx.data.profile.getTempBasal(sbx.time); var response = translate('virtAsstUnknown'); - var preamble = ''; + var pwd = _.get(slots, 'pwd.value'); + var preamble = pwd ? translate('virtAsstPreamble3person', { + params: [ + pwd + ] + }) : translate('virtAsstPreamble'); if (basalValue.treatment) { - preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', { - params: [ - slots.pwd.value - ] - }) : translate('virtAsstPreamble'); var minutesLeft = moment(basalValue.treatment.endmills).from(moment(sbx.time)); response = translate('virtAsstBasalTemp', { params: [ @@ -130,11 +131,6 @@ function init (ctx) { ] }); } else { - preamble = (slots && slots.pwd && slots.pwd.value) ? translate('virtAsstPreamble3person', { - params: [ - slots.pwd.value - ] - }) : translate('virtAsstPreamble'); response = translate('virtAsstBasal', { params: [ preamble, diff --git a/lib/plugins/bgnow.js b/lib/plugins/bgnow.js index 512a23805c2..f3d835788bf 100644 --- a/lib/plugins/bgnow.js +++ b/lib/plugins/bgnow.js @@ -146,12 +146,12 @@ function init (ctx) { bgnow.calcDelta = function calcDelta (recent, previous, sbx) { if (_.isEmpty(recent)) { - console.info('all buckets are empty'); + //console.info('No recent CGM data is available'); return null; } if (_.isEmpty(previous)) { - console.info('previous bucket not found, not calculating delta'); + //console.info('previous bucket not found, not calculating delta'); return null; } diff --git a/lib/plugins/cob.js b/lib/plugins/cob.js index c6d4c4fdf8f..250614ecfd6 100644 --- a/lib/plugins/cob.js +++ b/lib/plugins/cob.js @@ -293,11 +293,13 @@ function init (ctx) { function virtAsstCOBHandler (next, slots, sbx) { var response = ''; - var value = (sbx.properties.cob && sbx.properties.cob.cob) ? sbx.properties.cob.cob : 0; - if (slots && slots.pwd && slots.pwd.value) { + var cob = _.get(sbx, 'properties.cob.cob'); + var pwd = _.get(slots, 'pwd.value'); + var value = cob ? cob : 0; + if (pwd) { response = translate('virtAsstCob3person', { params: [ - slots.pwd.value.replace('\'s', '') + pwd.replace('\'s', '') , value ] }); diff --git a/lib/plugins/dbsize.js b/lib/plugins/dbsize.js index 1698fa050b3..1b6b43da8ed 100644 --- a/lib/plugins/dbsize.js +++ b/lib/plugins/dbsize.js @@ -1,6 +1,7 @@ 'use strict'; var levels = require('../levels'); +var _ = require('lodash'); function init (ctx) { var translate = ctx.language.translate; @@ -117,11 +118,14 @@ function init (ctx) { }; function virtAsstDatabaseSizeHandler (next, slots, sbx) { - if (sbx.properties.dbsize.display) { + var display = _.get(sbx, 'properties.dbsize.display'); + if (display) { + var dataSize = _.get(sbx, 'properties.dbsize.details.dataSize'); + var dataPercentage = _.get(sbx, 'properties.dbsize.dataPercentage'); var response = translate('virtAsstDatabaseSize', { params: [ - sbx.properties.dbsize.details.dataSize - , sbx.properties.dbsize.dataPercentage + dataSize + , dataPercentage ] }); next(translate('virtAsstTitleDatabaseSize'), response); @@ -133,13 +137,8 @@ function init (ctx) { dbsize.virtAsst = { intentHandlers: [ { - // for backwards compatibility - intent: 'DatabaseSize' - , intentHandler: virtAsstDatabaseSizeHandler - } - , { intent: 'MetricNow' - , metrics: ['database size', 'file size', 'db size', 'data size'] + , metrics: ['db size'] , intentHandler: virtAsstDatabaseSizeHandler } ] diff --git a/lib/plugins/index.js b/lib/plugins/index.js index 5a6cb2822da..d6bae73bdbc 100644 --- a/lib/plugins/index.js +++ b/lib/plugins/index.js @@ -74,6 +74,8 @@ function init (ctx) { , require('./treatmentnotify')(ctx) , require('./timeago')(ctx) , require('./basalprofile')(ctx) + , require('./dbsize')(ctx) + , require('./runtimestate')(ctx) ]; plugins.registerServerDefaults = function registerServerDefaults () { diff --git a/lib/plugins/iob.js b/lib/plugins/iob.js index 96bea03b3ff..cdcc15706e3 100644 --- a/lib/plugins/iob.js +++ b/lib/plugins/iob.js @@ -262,10 +262,11 @@ function init(ctx) { } function getIob(sbx) { - if (sbx.properties.iob && sbx.properties.iob.iob !== 0) { + var iob = _.get(sbx, 'properties.iob.iob'); + if (iob !== 0) { return translate('virtAsstIobUnits', { params: [ - utils.toFixed(sbx.properties.iob.iob) + utils.toFixed(iob) ] }); } diff --git a/lib/plugins/loop.js b/lib/plugins/loop.js index 46d16738787..e7d3ae91c93 100644 --- a/lib/plugins/loop.js +++ b/lib/plugins/loop.js @@ -529,13 +529,14 @@ function init (ctx) { }; function virtAsstForecastHandler (next, slots, sbx) { - if (sbx.properties.loop.lastLoop.predicted) { - var forecast = sbx.properties.loop.lastLoop.predicted.values; + var predicted = _.get(sbx, 'properties.loop.lastLoop.predicted'); + if (predicted) { + var forecast = predicted.values; var max = forecast[0]; var min = forecast[0]; var maxForecastIndex = Math.min(6, forecast.length); - var startPrediction = moment(sbx.properties.loop.lastLoop.predicted.startDate); + var startPrediction = moment(predicted.startDate); var endPrediction = startPrediction.clone().add(maxForecastIndex * 5, 'minutes'); if (endPrediction.valueOf() < sbx.time) { next(translate('virtAsstTitleLoopForecast'), translate('virtAsstForecastUnavailable')); @@ -573,8 +574,9 @@ function init (ctx) { } function virtAsstLastLoopHandler (next, slots, sbx) { - if (sbx.properties.loop.lastLoop) { - console.log(JSON.stringify(sbx.properties.loop.lastLoop)); + var lastLoop = _.get(sbx, 'properties.loop.lastLoop') + if (lastLoop) { + console.log(JSON.stringify(lastLoop)); var response = translate('virtAsstLastLoop', { params: [ moment(sbx.properties.loop.lastOkMoment).from(moment(sbx.time)) diff --git a/lib/plugins/openaps.js b/lib/plugins/openaps.js index 037680960d2..cf5e240ce99 100644 --- a/lib/plugins/openaps.js +++ b/lib/plugins/openaps.js @@ -560,10 +560,11 @@ function init (ctx) { }; function virtAsstForecastHandler (next, slots, sbx) { - if (sbx.properties.openaps && sbx.properties.openaps.lastEventualBG) { + var lastEventualBG = _.get(sbx, 'properties.openaps.lastEventualBG'); + if (lastEventualBG) { var response = translate('virtAsstOpenAPSForecast', { params: [ - sbx.properties.openaps.lastEventualBG + lastEventualBG ] }); next(translate('virtAsstTitleOpenAPSForecast'), response); @@ -573,11 +574,11 @@ function init (ctx) { } function virtAsstLastLoopHandler (next, slots, sbx) { - if (sbx.properties.openaps.lastLoopMoment) { - console.log(JSON.stringify(sbx.properties.openaps.lastLoopMoment)); + var lastLoopMoment = _.get(sbx, 'properties.openaps.lastLoopMoment'); + if (lastLoopMoment) { var response = translate('virtAsstLastLoop', { params: [ - moment(sbx.properties.openaps.lastLoopMoment).from(moment(sbx.time)) + moment(lastLoopMoment).from(moment(sbx.time)) ] }); next(translate('virtAsstTitleLastLoop'), response); diff --git a/lib/plugins/pump.js b/lib/plugins/pump.js index 7e71c21e1b1..52dc7ade769 100644 --- a/lib/plugins/pump.js +++ b/lib/plugins/pump.js @@ -136,7 +136,7 @@ function init (ctx) { }; function virtAsstReservoirHandler (next, slots, sbx) { - var reservoir = sbx.properties.pump.pump.reservoir; + var reservoir = _.get(sbx, 'properties.pump.pump.reservoir'); if (reservoir || reservoir === 0) { var response = translate('virtAsstReservoir', { params: [ diff --git a/lib/plugins/pushover.js b/lib/plugins/pushover.js index 99fc22697a4..8c63a905e00 100644 --- a/lib/plugins/pushover.js +++ b/lib/plugins/pushover.js @@ -127,7 +127,10 @@ function setupPushover (env) { if (apiToken && (userKeys.length > 0 || alarmKeys.length > 0 || announcementKeys.length > 0)) { var pushoverAPI = new Pushover({ - token: apiToken + token: apiToken, + onerror: function(error) { + console.error('Pushover error', error); + } }); pushoverAPI.apiToken = apiToken; diff --git a/lib/plugins/rawbg.js b/lib/plugins/rawbg.js index 3248126b046..a784f49363f 100644 --- a/lib/plugins/rawbg.js +++ b/lib/plugins/rawbg.js @@ -107,10 +107,11 @@ function init (ctx) { }; function virtAsstRawBGHandler (next, slots, sbx) { - if (sbx.properties.rawbg.mgdl) { + var rawBg = _.get(sbx, 'properties.rawbg.mgdl'); + if (rawBg) { var response = translate('virtAsstRawBG', { params: [ - sbx.properties.rawbg.mgdl + rawBg ] }); next(translate('virtAsstTitleRawBG'), response); diff --git a/lib/plugins/runtimestate.js b/lib/plugins/runtimestate.js new file mode 100644 index 00000000000..0447da0cc00 --- /dev/null +++ b/lib/plugins/runtimestate.js @@ -0,0 +1,23 @@ +'use strict'; + +function init() { + + var runtime = { + name: 'runtimestate' + , label: 'Runtime state' + , pluginType: 'fake' + }; + + runtime.setProperties = function setProperties(sbx) { + sbx.offerProperty('runtimestate', function setProp ( ) { + return { + state: sbx.runtimeState + }; + }); + }; + + return runtime; + +} + +module.exports = init; \ No newline at end of file diff --git a/lib/plugins/simplealarms.js b/lib/plugins/simplealarms.js index 9b975dddebe..17529eabee8 100644 --- a/lib/plugins/simplealarms.js +++ b/lib/plugins/simplealarms.js @@ -12,6 +12,7 @@ function init() { }; simplealarms.checkNotifications = function checkNotifications(sbx) { + var lastSGVEntry = sbx.lastSGVEntry() , scaledSGV = sbx.scaleEntry(lastSGVEntry) ; @@ -37,27 +38,31 @@ function init() { simplealarms.compareBGToTresholds = function compareBGToTresholds(scaledSGV, sbx) { var result = { level: levels.INFO }; - if (scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgHigh)) { + if (sbx.settings.alarmUrgentHigh && scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgHigh)) { result.level = levels.URGENT; result.title = levels.toDisplay(levels.URGENT) + ' HIGH'; result.pushoverSound = 'persistent'; result.eventName = 'high'; - } else if (scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) { - result.level = levels.WARN; - result.title = levels.toDisplay(levels.WARN) + ' HIGH'; - result.pushoverSound = 'climb'; - result.eventName = 'high'; - } else if (scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgLow)) { + } else + if (sbx.settings.alarmHigh && scaledSGV > sbx.scaleMgdl(sbx.settings.thresholds.bgTargetTop)) { + result.level = levels.WARN; + result.title = levels.toDisplay(levels.WARN) + ' HIGH'; + result.pushoverSound = 'climb'; + result.eventName = 'high'; + } + + if (sbx.settings.alarmUrgentLow && scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgLow)) { result.level = levels.URGENT; result.title = levels.toDisplay(levels.URGENT) + ' LOW'; result.pushoverSound = 'persistent'; result.eventName = 'low'; - } else if (scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) { + } else if (sbx.settings.alarmLow && scaledSGV < sbx.scaleMgdl(sbx.settings.thresholds.bgTargetBottom)) { result.level = levels.WARN; result.title = levels.toDisplay(levels.WARN) + ' LOW'; result.pushoverSound = 'falling'; result.eventName = 'low'; } + return result; }; diff --git a/lib/plugins/upbat.js b/lib/plugins/upbat.js index dc603054ecb..71547eca6a2 100644 --- a/lib/plugins/upbat.js +++ b/lib/plugins/upbat.js @@ -223,10 +223,11 @@ function init(ctx) { }; function virtAsstUploaderBatteryHandler (next, slots, sbx) { - if (sbx.properties.upbat.display) { + var upBat = _.get(sbx, 'properties.upbat.display'); + if (upBat) { var response = translate('virtAsstUploaderBattery', { params: [ - sbx.properties.upbat.display + upBat ] }); next(translate('virtAsstTitleUploaderBattery'), response); diff --git a/lib/plugins/virtAsstBase.js b/lib/plugins/virtAsstBase.js index e0d103672a2..781f56969cf 100644 --- a/lib/plugins/virtAsstBase.js +++ b/lib/plugins/virtAsstBase.js @@ -81,7 +81,7 @@ function init(env, ctx) { }; virtAsstBase.setupVirtAsstHandlers = function (configuredPlugin) { - ctx.plugins.eachEnabledPlugin(function (plugin){ + ctx.plugins.eachEnabledPlugin(function (plugin) { if (plugin.virtAsst) { if (plugin.virtAsst.intentHandlers) { console.log('Plugin "' + plugin.name + '" supports Virtual Assistants'); diff --git a/lib/plugins/xdripjs.js b/lib/plugins/xdripjs.js index dc44aad2988..dd5b55eb816 100644 --- a/lib/plugins/xdripjs.js +++ b/lib/plugins/xdripjs.js @@ -324,10 +324,11 @@ function init(ctx) { function virtAsstGenericCGMHandler(translateItem, field, next, sbx) { var response; - if (sbx.properties.sensorState && sbx.properties.sensorState[field]) { + var state = _.get(sbx, 'properties.sensorState.'+field); + if (state) { response = translate('virtAsstCGM'+translateItem, { params:[ - sbx.properties.sensorState[field] + state , moment(sbx.properties.sensorState.lastStateTime).from(moment(sbx.time)) ] }); @@ -355,10 +356,11 @@ function init(ctx) { , metrics: ['cgm session age'] , intentHandler: function(next, slots, sbx){ var response; + var lastSessionStart = _.get(sbx, 'properties.sensorState.lastSessionStart'); // session start is only valid if in a session - if (sbx.properties.sensorState && sbx.properties.sensorState.lastSessionStart) { - if (sbx.properties.sensorState.lastState != 0x1) { - var duration = moment.duration(moment().diff(moment(sbx.properties.sensorState.lastSessionStart))); + if (lastSessionStart) { + if (_.get(sbx, 'properties.sensorState.lastState') != 0x1) { + var duration = moment.duration(moment().diff(moment(lastSessionStart))); response = translate('virtAsstCGMSessAge', { params: [ duration.days(), @@ -384,10 +386,11 @@ function init(ctx) { intent: 'MetricNow' , metrics: ['cgm tx age'] , intentHandler: function(next, slots, sbx){ + var lastTxActivation = _.get(sbx, 'properties.sensorState.lastTxActivation'); next( translate('virtAsstTitleCGMTxAge'), - (sbx.properties.sensorState && sbx.properties.sensorState.lastTxActivation) - ? translate('virtAsstCGMTxAge', {params:[moment().diff(moment(sbx.properties.sensorState.lastTxActivation), 'days')]}) + lastTxActivation + ? translate('virtAsstCGMTxAge', {params:[moment().diff(moment(lastTxActivation), 'days')]}) : translate('virtAsstUnknown') ); } @@ -402,22 +405,24 @@ function init(ctx) { , metrics: ['cgm battery'] , intentHandler: function(next, slots, sbx){ var response; - var sensor = sbx.properties.sensorState; - if (sensor && (sensor.lastVoltageA || sensor.lastVoltageB)) { - if (sensor.lastVoltageA && sensor.lastVoltageB) { + var lastVoltageA = _.get(sbx, 'properties.sensorState.lastVoltageA'); + var lastVoltageB = _.get(sbx, 'properties.sensorState.lastVoltageB'); + var lastBatteryTimestamp = _.get(sbx, 'properties.sensorState.lastBatteryTimestamp'); + if (lastVoltageA || lastVoltageB) { + if (lastVoltageA && lastVoltageB) { response = translate('virtAsstCGMBattTwo', { params:[ - (sensor.lastVoltageA / 100) - , (sensor.lastVoltageB / 100) - , moment(sensor.lastBatteryTimestamp).from(moment(sbx.time)) + (lastVoltageA / 100) + , (lastVoltageB / 100) + , moment(lastBatteryTimestamp).from(moment(sbx.time)) ] }); } else { - var finalValue = sensor.lastVoltageA ? sensor.lastVoltageA : sensor.lastVoltageB; + var finalValue = lastVoltageA ? lastVoltageA : lastVoltageB; response = translate('virtAsstCGMBattOne', { params:[ (finalValue / 100) - , moment(sensor.lastBatteryTimestamp).from(moment(sbx.time)) + , moment(lastBatteryTimestamp).from(moment(sbx.time)) ] }); } diff --git a/lib/sandbox.js b/lib/sandbox.js index 4bcee3b40e4..6805bee6982 100644 --- a/lib/sandbox.js +++ b/lib/sandbox.js @@ -45,6 +45,7 @@ function init () { reset(); sbx.runtimeEnvironment = 'server'; + sbx.runtimeState = ctx.runtimeState; sbx.time = Date.now(); sbx.settings = env.settings; sbx.data = ctx.ddata.clone(); diff --git a/lib/server/booterror.js b/lib/server/booterror.js index d8735e94451..92de6cbc81b 100644 --- a/lib/server/booterror.js +++ b/lib/server/booterror.js @@ -26,7 +26,7 @@ function bootError(env, ctx) { } else { message = JSON.stringify(_.pick(obj.err, Object.getOwnPropertyNames(obj.err))); } - return '
' + obj.desc + '
' + message.replace(/\\n/g, '
') + '
'; + return '
' + obj.desc + '
' + message.replace(/\\n/g, '
') + '
'; }).join(' '); res.render('error.html', { diff --git a/lib/server/bootevent.js b/lib/server/bootevent.js index 6247645b3d2..ff4e9110f00 100644 --- a/lib/server/bootevent.js +++ b/lib/server/bootevent.js @@ -6,6 +6,11 @@ var UPDATE_THROTTLE = 5000; function boot (env, language) { + function startBoot(ctx, next) { + ctx.runtimeState = 'booting'; + next(); + } + ////////////////////////////////////////////////// // Check Node version. // Latest Node 8 LTS and Latest Node 10 LTS are recommended and supported. @@ -25,30 +30,21 @@ function boot (env, language) { var semver = require('semver'); var nodeVersion = process.version; - if ( semver.satisfies(nodeVersion, '^8.15.1') || semver.satisfies(nodeVersion, '^10.16.0')) { - //Latest Node 8 LTS and Latest Node 10 LTS are recommended and supported. + const isLTS = process.release.lts ? true : false; + + if (!isLTS) { + console.log( 'ERROR: Node version ' + nodeVersion + ' is not supported. Please use a secure LTS version or upgrade your Node'); + process.exit(1); + } + + if (semver.satisfies(nodeVersion, '^12.0.0') || semver.satisfies(nodeVersion, '^10.0.0')) { + //Latest Node 10 LTS and Node 12 LTS are recommended and supported. //Require at least Node 8 LTS and Node 10 LTS without known security issues console.debug('Node LTS version ' + nodeVersion + ' is supported'); next(); } - else if ( semver.eq(nodeVersion, '10.15.2')) { - //Latest Node version on Azure is tolerated, but not recommended - console.log('WARNING: Node version v10.15.2 and Microsoft Azure are not recommended.'); - console.log('WARNING: Please migrate to another hosting provider. Your Node version is outdated and insecure'); - next(); - } - else if ( semver.satisfies(nodeVersion, '^12.6.0')) { - //Latest Node version - console.debug('Node version ' + nodeVersion + ' is not a LTS version. Not recommended. Not supported'); - next(); - } else { - // Other versions will not start - console.log( 'ERROR: Node version ' + nodeVersion + ' is not supported. Please use a secure LTS version or upgrade your Node'); - process.exit(1); - } } - function checkEnv (ctx, next) { ctx.language = language; if (env.err) { @@ -137,7 +133,7 @@ function boot (env, language) { if (err) { console.info('ERROR CONNECTING TO MONGO', err); ctx.bootErrors = ctx.bootErrors || [ ]; - ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err}); + ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err.message}); } console.log('Mongo Storage system ready'); ctx.store = store; @@ -147,7 +143,7 @@ function boot (env, language) { } catch (err) { console.info('ERROR CONNECTING TO MONGO', err); ctx.bootErrors = ctx.bootErrors || [ ]; - ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err}); + ctx.bootErrors.push({'desc': 'Unable to connect to Mongo', err: err.message}); next(); } } @@ -255,7 +251,7 @@ function boot (env, language) { }); ctx.bus.on('data-loaded', function updatePlugins ( ) { - // console.info('reloading sandbox data'); + console.info('data loaded: reloading sandbox data and updating plugins'); var sbx = require('../sandbox')().serverInit(env, ctx); ctx.plugins.setProperties(sbx); ctx.notifications.initRequests(); @@ -264,6 +260,10 @@ function boot (env, language) { ctx.bus.emit('data-processed'); }); + ctx.bus.on('data-processed', function processed ( ) { + ctx.runtimeState = 'loaded'; + }); + ctx.bus.on('notification', ctx.pushnotify.emitNotification); next( ); @@ -298,12 +298,14 @@ function boot (env, language) { return next(); } + ctx.runtimeState = 'booted'; ctx.bus.uptime( ); next( ); } return require('bootevent')( ) + .acquire(startBoot) .acquire(checkNodeVersion) .acquire(checkEnv) .acquire(augmentSettings) diff --git a/lib/settings.js b/lib/settings.js index 845cea07628..98a53b93a83 100644 --- a/lib/settings.js +++ b/lib/settings.js @@ -167,7 +167,7 @@ function init () { } //TODO: getting sent in status.json, shouldn't be - settings.DEFAULT_FEATURES = ['bgnow', 'delta', 'direction', 'timeago', 'devicestatus', 'upbat', 'errorcodes', 'profile', 'dbsize']; + settings.DEFAULT_FEATURES = ['bgnow', 'delta', 'direction', 'timeago', 'devicestatus', 'upbat', 'errorcodes', 'profile', 'dbsize', 'runtimestate', 'basal', 'careportal']; var wasSet = []; diff --git a/lib/storage/mongo-storage.js b/lib/storage/mongo-storage.js index 39c1a81e641..8c2533873c7 100644 --- a/lib/storage/mongo-storage.js +++ b/lib/storage/mongo-storage.js @@ -36,59 +36,71 @@ function init (env, cb, forceNewConnection) { MongoClient.connect(env.storageURI, options) .then(client => { - console.log('Successfully established a connected to MongoDB'); - - var dbName = env.storageURI.split('/').pop().split('?'); - dbName = dbName[0]; // drop Connection Options - mongo.db = client.db(dbName); - connection = mongo.db; - mongo.client = client; - // If there is a valid callback, then invoke the function to perform the callback - - if (cb && cb.call) { - cb(null, mongo); - } - }) - .catch(err => { - if (err.message && err.message.includes('AuthenticationFailed')) { - console.log('Authentication to Mongo failed'); - cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null); - return; - } - - if (err.name && err.name === "MongoNetworkError") { - var timeout = (i > 15) ? 60000 : i * 3000; - console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err); - setTimeout(connect_with_retry, timeout, i + 1); - if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null); - } else { - cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message)); + console.log('Successfully established a connected to MongoDB'); + + var dbName = env.storageURI.split('/').pop().split('?'); + dbName = dbName[0]; // drop Connection Options + mongo.db = client.db(dbName); + connection = mongo.db; + mongo.client = client; + + mongo.db.command({ connectionStatus: 1 }).then( + result => { + const roles = result.authInfo.authenticatedUserRoles; + if (roles.length > 0 && roles[0].role == 'readAnyDatabase') { + console.error('Mongo user is read only'); + cb(new Error('MongoDB connection is in read only mode! Go back to MongoDB configuration and check your database user has read and write access.'), null); + } + + console.log('Mongo user role seems ok:', roles); + + // If there is a valid callback, then invoke the function to perform the callback + if (cb && cb.call) { + cb(null, mongo); + } } - }); + ); + }) + .catch(err => { + if (err.message && err.message.includes('AuthenticationFailed')) { + console.log('Authentication to Mongo failed'); + cb(new Error('MongoDB authentication failed! Double check the URL has the right username and password in MONGODB_URI.'), null); + return; + } + + if (err.name && err.name === "MongoNetworkError") { + var timeout = (i > 15) ? 60000 : i * 3000; + console.log('Error connecting to MongoDB: %j - retrying in ' + timeout / 1000 + ' sec', err); + setTimeout(connect_with_retry, timeout, i + 1); + if (i == 1) cb(new Error('MongoDB connection failed! Double check the MONGODB_URI setting in Heroku.'), null); + } else { + cb(new Error('MONGODB_URI ' + env.storageURI + ' seems invalid: ' + err.message)); + } + }); - }; + }; - return connect_with_retry(1); + return connect_with_retry(1); - } } + } - mongo.collection = function get_collection (name) { - return connection.collection(name); - }; - - mongo.ensureIndexes = function ensureIndexes (collection, fields) { - fields.forEach(function(field) { - console.info('ensuring index for: ' + field); - collection.createIndex(field, { 'background': true }, function(err) { - if (err) { - console.error('unable to ensureIndex for: ' + field + ' - ' + err); - } - }); + mongo.collection = function get_collection (name) { + return connection.collection(name); + }; + + mongo.ensureIndexes = function ensureIndexes (collection, fields) { + fields.forEach(function(field) { + console.info('ensuring index for: ' + field); + collection.createIndex(field, { 'background': true }, function(err) { + if (err) { + console.error('unable to ensureIndex for: ' + field + ' - ' + err); + } }); - }; + }); + }; - return maybe_connect(cb); - } + return maybe_connect(cb); +} - module.exports = init; +module.exports = init; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 14b8d343cf4..a137dcd1533 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nightscout", - "version": "14.0.6", + "version": "14.0.7", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -3405,12 +3405,62 @@ } }, "env-cmd": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-8.0.2.tgz", - "integrity": "sha512-gHX8MnQXw1iS7dc2KeJdBdxca7spIkxkNwIuORLwm8kDg6xHh5wWnv1Yv3pc64nLZR6kufQSCmwTz16sRmd/rg==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/env-cmd/-/env-cmd-10.1.0.tgz", + "integrity": "sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA==", "dev": true, "requires": { - "cross-spawn": "^6.0.5" + "commander": "^4.0.0", + "cross-spawn": "^7.0.0" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } } }, "errno": { diff --git a/package.json b/package.json index ec94894a060..bbc6f063262 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nightscout", - "version": "14.0.6", + "version": "14.0.7", "description": "Nightscout acts as a web-based CGM (Continuous Glucose Montinor) to allow multiple caregivers to remotely view a patients glucose data in realtime.", "license": "AGPL-3.0", "author": "Nightscout Team", @@ -27,18 +27,18 @@ }, "scripts": { "start": "node server.js", - "test": "env-cmd ./my.test.env mocha --exit tests/*.test.js", - "test-single": "env-cmd ./my.test.env mocha --exit tests/$TEST.test.js", - "test-ci": "env-cmd ./ci.test.env nyc --reporter=lcov --reporter=text-summary mocha --exit tests/*.test.js", + "test": "env-cmd -f ./my.test.env mocha --exit tests/*.test.js", + "test-single": "env-cmd -f ./my.test.env mocha --exit tests/$TEST.test.js", + "test-ci": "env-cmd -f ./ci.test.env nyc --reporter=lcov --reporter=text-summary mocha --exit tests/*.test.js", "env": "env", "postinstall": "webpack --mode production --config webpack.config.js && npm run-script update-buster", "bundle": "webpack --mode production --config webpack.config.js && npm run-script update-buster", "bundle-dev": "webpack --mode development --config webpack.config.js && npm run-script update-buster", "bundle-analyzer": "webpack --mode development --config webpack.config.js --profile --json > stats.json && webpack-bundle-analyzer stats.json", "update-buster": "node bin/generateCacheBuster.js >tmp/cacheBusterToken", - "coverage": "cat ./coverage/lcov.info | env-cmd ./ci.test.env codacy-coverage", - "dev": "env-cmd ./my.env nodemon server.js 0.0.0.0", - "prod": "env-cmd ./my.prod.env node server.js 0.0.0.0", + "coverage": "cat ./coverage/lcov.info | env-cmd -f ./ci.test.env codacy-coverage", + "dev": "env-cmd -f ./my.env nodemon server.js 0.0.0.0", + "prod": "env-cmd -f ./my.prod.env node server.js 0.0.0.0", "lint": "eslint lib" }, "main": "server.js", @@ -57,8 +57,8 @@ } }, "engines": { - "node": "^10.15.2 || ^8.15.1", - "npm": "^6.4.1" + "node": "^10.22.0 || ^12.18.4", + "npm": "^6.14.6" }, "dependencies": { "@babel/core": "^7.11.1", @@ -126,7 +126,7 @@ "benv": "^3.3.0", "codacy-coverage": "^3.4.0", "csv-parse": "^4.12.0", - "env-cmd": "^8.0.2", + "env-cmd": "^10.1.0", "eslint": "^6.8.0", "eslint-loader": "^2.2.1", "mocha": "^8.1.1", diff --git a/swagger.json b/swagger.json index 83f28a0469f..d4f9cbde296 100755 --- a/swagger.json +++ b/swagger.json @@ -8,7 +8,7 @@ "info": { "title": "Nightscout API", "description": "Own your DData with the Nightscout API", - "version": "14.0.6", + "version": "14.0.7", "license": { "name": "AGPL 3", "url": "https://www.gnu.org/licenses/agpl.txt" diff --git a/swagger.yaml b/swagger.yaml index 7429d96a309..98d89401be6 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -4,7 +4,7 @@ servers: info: title: Nightscout API description: Own your DData with the Nightscout API - version: 14.0.6 + version: 14.0.7 license: name: AGPL 3 url: 'https://www.gnu.org/licenses/agpl.txt' diff --git a/tests/api.entries.test.js b/tests/api.entries.test.js index 098b5c45663..6c0c3f14e45 100644 --- a/tests/api.entries.test.js +++ b/tests/api.entries.test.js @@ -307,4 +307,66 @@ describe('Entries REST api', function ( ) { }); }); + it('post multipole entries, query, delete, verify gone', function (done) { + // insert a glucose entry - needs to be unique from example data + console.log('Inserting glucose entry') + request(self.app) + .post('/entries/') + .set('api-secret', self.env.api_secret || '') + .send([{ + "type": "sgv", "sgv": "199", "dateString": "2014-07-20T00:44:15.000-07:00" + , "date": 1405791855000, "device": "dexcom", "direction": "NOT COMPUTABLE" + }, { + "type": "sgv", "sgv": "200", "dateString": "2014-07-20T00:44:15.001-07:00" + , "date": 1405791855001, "device": "dexcom", "direction": "NOT COMPUTABLE" + }]) + .expect(200) + .end(function (err) { + if (err) { + done(err); + } else { + // make sure treatment was inserted successfully + console.log('Ensuring glucose entry was inserted successfully'); + request(self.app) + .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') + .set('api-secret', self.env.api_secret || '') + .expect(200) + .expect(function (response) { + var entry = response.body[0]; + response.body.length.should.equal(2); + entry.sgv.should.equal('200'); + entry.utcOffset.should.equal(-420); + }) + .end(function (err) { + if (err) { + done(err); + } else { + // delete the glucose entry + console.log('Deleting test glucose entry'); + request(self.app) + .delete('/entries.json?find[dateString][$gte]=2014-07-20&count=100') + .set('api-secret', self.env.api_secret || '') + .expect(200) + .end(function (err) { + if (err) { + done(err); + } else { + // make sure it was deleted + console.log('Testing if glucose entries were deleted'); + request(self.app) + .get('/entries.json?find[dateString][$gte]=2014-07-20&count=100') + .set('api-secret', self.env.api_secret || '') + .expect(200) + .expect(function (response) { + response.body.length.should.equal(0); + }) + .end(done); + } + }); + } + }); + } + }); + }); + }); diff --git a/tests/api3.basic.test.js b/tests/api3.basic.test.js index fc7a885269f..d13b8628562 100644 --- a/tests/api3.basic.test.js +++ b/tests/api3.basic.test.js @@ -23,15 +23,6 @@ describe('Basic REST API3', function() { }); - it('GET /swagger', async () => { - let res = await request(self.app) - .get('/api/v3/swagger.yaml') - .expect(200); - - res.header['content-length'].should.be.above(0); - }); - - it('GET /version', async () => { let res = await request(self.app) .get('/api/v3/version') diff --git a/tests/dbsize.test.js b/tests/dbsize.test.js index 0a66bb3ad6d..ce95f8652c0 100644 --- a/tests/dbsize.test.js +++ b/tests/dbsize.test.js @@ -300,18 +300,13 @@ describe('Database Size', function() { var dbsize = require('../lib/plugins/dbsize')(ctx); dbsize.setProperties(sbx); - dbsize.virtAsst.intentHandlers.length.should.equal(2); + dbsize.virtAsst.intentHandlers.length.should.equal(1); dbsize.virtAsst.intentHandlers[0].intentHandler(function next (title, response) { title.should.equal('Database file size'); - response.should.equal('450 MiB that is 90% of available database space'); + response.should.equal('450 MiB. That is 90% of available database space.'); - dbsize.virtAsst.intentHandlers[1].intentHandler(function next (title, response) { - title.should.equal('Database file size'); - response.should.equal('450 MiB that is 90% of available database space'); - - done(); - }, [], sbx); + done(); }, [], sbx); diff --git a/tests/fixtures/default-server-settings.js b/tests/fixtures/default-server-settings.js index 113a5fa4aeb..ac3d31d25a0 100644 --- a/tests/fixtures/default-server-settings.js +++ b/tests/fixtures/default-server-settings.js @@ -33,4 +33,5 @@ module.exports = { } , extendedSettings: { } } + , runtimeState: 'loaded' }; \ No newline at end of file diff --git a/views/index.html b/views/index.html index dbff801392f..8e60b30f471 100644 --- a/views/index.html +++ b/views/index.html @@ -730,7 +730,7 @@ reg.addEventListener('updatefound', () => { console.log('Service worker update detected'); reg.update(); - const newWorker = reg.installing; + var newWorker = reg.installing; newWorker.addEventListener('statechange', (state) => { console.log('New worker state change', state); window.location.reload(true); diff --git a/views/reportindex.html b/views/reportindex.html index 8d02bf08f58..ea1284b6cd4 100644 --- a/views/reportindex.html +++ b/views/reportindex.html @@ -94,9 +94,9 @@ Target BG range bottom: - + top: - +