1676601660
You can use the length
property to check if a string is empty in JavaScript. If the string's length is equal to 0, then it is empty. Otherwise, the string is not empty.
const str = ''
if (str.length === 0) {
console.log(`String is empty ✅`)
} else {
console.log(`String is not empty ❌`)
}
// String is empty ✅
If the string contains leading or trailing whitespace, you should use the trim()
method to remove whitespace before checking if it is empty:
const str = ' '
if (str.trim().length === 0) {
console.log(`String is empty ✅`)
} else {
console.log(`String is not empty ❌`)
}
// String is empty ✅
The trim() method removes the leading and trailing spaces from a string. It returns an empty string if the string only contains spaces.
Alternatively, you could also use the strict equality operator (===)
to check whether a string is empty or not:
const str = ''
console.log(str === '') // true
console.log(0 === '') // false
console.log(false === '') // false
console.log([] === '') // false
console.log(null === '') // false
console.log(undefined === '') // false
As you can see above, the strict equality operator returns false
for null
, undefined
, and false
values in the comparison because these are special values.
To check if a string is truthy and contains one or more characters, use the following code:
const str = 'js'
if (str) {
// `str` variable is NOT false, undefined,
// null, empty string, NaN
console.log(`String is truthy 💯`)
}
// String is truthy 💯
A variable is truthy if it is not an empty string, 0, null, undefined, false, or NaN.
Original article source at: https://attacomsian.com/
1676422800
Objects are used to store a collection of properties, each of which may be thought of as an association between a name (or key) and a value (a collection of key-value pairs).
In this guide, we will explore many JavaScript methods on how to check if an object is empty. We'll be using Vanilla JavaScript, as well as common libraries such as lodash and underscore.
When it comes to small applications that don't require external dependencies - checking whether an object is empty is best done with pure JavaScript. However, if your application already has external libraries such as lodash and underscore - they offer great ways to perform these checks as well.
Checking if an object is empty or not is a basic and frequent operation, however, there are several methods for determining whether it's empty or not.
Let's start by creating an empty Object with the object literal syntax:
const emptyObject = {}
Object.keys()
is a static method that returns an Array when we pass an object to it, which contains the property names (keys) belonging to that object. We can check whether the length
of this array is 0
or higher - denoting whether any keys are present or not. If no keys are present, the object is empty:
Object.keys(obj).length === 0 && obj.constructor === Object;
Note: The constructor check makes sure the passed argument is indeed an object.
We could also create a reusable function, if you're using the check multiple times in the project:
const isEmptyObject = (obj) => {
return Object.keys(obj).length === 0 && obj.constructor === Object;
}
console.log(isEmptyObject(emptyObject)); // true
This is by far the simplest method for determining whether an object is empty, though, it's a bit verbose. We'll remove this verbosity with following approaches - after we take a look at the Object.values()
and Object.entries()
static methods, which can be used in much the same way as Object.keys()
.
Using the Object.values() Method
Just as with keys - if an object has no values
associated (not even an undefined
/null
) - it's empty:
const isEmptyObject = (obj) => {
return Object.values(obj).length === 0 && obj.constructor === Object;
}
console.log(isEmptyObject(emptyObject)); // true
Using the Object.entries() Method
The entries()
method represents all key-value pairs (entries), which can be used as a wrapper for both of the approaches above:
const isEmptyObject = (obj) => {
return Object.entries(obj).length === 0 && obj.constructor === Object;
}
console.log(isEmptyObject(emptyObject)); // true
For browsers that don't support the keys()
, values()
and entries()
methods - you can explicitly loop through the properties! You can wrap this logic within a method that returns true
if no properties were found, and false
if properties were found:
const isEmptyObject = (objectName) => {
for (var prop in objectName) {
if (objectName.hasOwnProperty(prop)) {
return false;
}
}
return true;
}
console.log(isEmptyObject(emptyObject)); // true
This is one of the simplest method to use. When we stringify an object and the output is only an opening and closing bracket, we know the item is empty:
JSON.stringify(objectName) === '{}';
We could also easily be wrapped into a function:
const isEmptyObject = (objectName) => {
return JSON.stringify(objectName) === '{}';
}
console.log(isEmptyObject(emptyObject)); // true
Libraries help us write code faster, by incorporating advanced functionality, used and honed by countless other developers, instead of writing our own solutions.
Libraries are common, typically fast/optimized, and some are present in many projects due to how useful they are. Several of them can also be used for checking whether an object is empty or not. The majority of them offer excellent compatibility for older browsers.
Using Underscore and Lodash
Both lodash and underscore are utility libraries that offer a fair bit of common utilities. They're both typically imported as _
, and can be imported via a CDN:
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.2/underscore-umd-min.js"></script>
Or installed a package manager such as NPM, and then imported via the require()
syntax:
$ npm install lodash
$ npm install underscore
const _ = require('lodash');
const _ = require('underscore');
Both libraries have the exact same syntax for checking whether an object is empty:
_.isEmpty();
This function works with any data structure - lists, arrays, strings, objects, etc. The function is a wrapper around the logic that checks the length of the object that was passed in, returning true
or false
:
_.isEmpty(emptyObject); // true
jQuery
jQuery is a popular JavaScript library, present in many projects around the world. Due to its light weight and features that expand the scope of JavaScript's built-in capabilities - it's become a staple.
jQuery can be imported via a CDN:
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
Or installed a package manager such as NPM, and then imported via the require()
syntax:
$ npm install jquery
It's typically imported as $
:
const $ = require('jquery');
Naturally, you can use it to check whether an object is empty or not:
$.isEmptyObject(emptyObject); // true
Ramda
Ramda is a functional JavaScript library! It never mutates data and supports the creation of purely functional pipelines. For those with a more functional programming background - it's a great library to feel at home with.
Ramda can be imported via a CDN:
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
Or installed a package manager such as NPM, and then imported via the require()
syntax:
$ npm install ramda
It's typically imported as R
:
const R = require('ramda');
If you're already using it - it offers an isEmpty()
function as well:
R.isEmpty(emptyObject); // true
Hoek
@hapi/hoek is part of the hapi ecosystem, and a popular utility method library for hapi-based apps. It offers a deepEqual()
method, that checks whether two objects are the same (depth-wise):
Hoek.deepEqual({}, emptyObject); // true
In this article, we have taken a look at how to check whether an object is empty or not in JavaScript. To this end - we've used several Vanilla JS approaches, jQuery, Underscore, Lodash, Ramda, Hoek and the JSON module.
Original article source at: https://stackabuse.com/
1671656340
RxJS pipelines are convenient ways to get work done in your applications. You can essentially tell the app the steps it needs to take, and it will go step by step through the pipeline. But what if one of the steps will potentially be empty, but you want the pipeline to continue? That’s where the defaultIfEmpty
operator can come in handy. I recently learned about it when I had a similar situation, and it worked perfectly for me.
I was recently working on an application where you needed to be able to add, edit, and delete data. The work needed to be done in a certain order: deletions first, then additions or edits. This is straightforward as long as there are actions for each of the above types to be done: at least one add, one edit, and one delete. But what happens if one of those types doesn’t need to be done in a given pipeline?
This is the situation I found myself in. If the delete observable was empty, nothing happened. I needed the pipeline to continue, however, and move on to adds and edits. I started searching around and found the defaultIfEmpty
operator, which solved my problem for me.
defaultIfEmpty
The defaultIfEmpty
operator does exactly what it sounds like: it provides a default value in the pipeline if the preceding observable doesn’t emit a value. This ensures that the pipeline doesn’t get stuck, but instead outputs a value.
Let’s look at a couple examples. First we’ll look at an example pipeline where there is a type for adds, edits, and deletes.
const deletions = [of('delete 1')];
const additions = [of('add 1')];
const edits = [of('edit 1')];
zip(...deletions)
.pipe(
tap((deletionResult) => console.log(deletionResult)),
switchMap(() => zip(...additions)),
tap((additionResult) => console.log(additionResult)),
switchMap(() => zip(...edits)),
tap((editsResult) => console.log(editsResult))
)
.subscribe();
In the above example, this pipeline will execute as expected. The deletion observables will run and emit a value, then the additions, then the edits. The result of all three sections will be logged to the console. Easy enough, right? But what do we do if we have no deletions to run?
const deletions2 = [];
const additions2 = [of('add 2')];
const edits2 = [of('edit 2')];
zip(...deletions2)
.pipe(
tap((deletionResult) => console.log(deletionResult)),
switchMap(() => zip(...additions2)),
tap((additionResult) => console.log(additionResult)),
switchMap(() => zip(...edits2)),
tap((editsResult) => console.log(editsResult))
)
.subscribe();
In this example, nothing gets logged to the console. We never move past the first step, because nothing is ever emitted from the initial zip(...deletions2)
portion of the pipeline. But just because we don’t have anything to delete doesn’t mean we don’t want to continue with adding and editing the other pieces. This is where the defaultIfEmpty
operator comes in handy. Insert it after a given step in the observable pipeline that could potentially emit no data. Then the pipeline will continue. Continuing with the above example, we can change it to the following to get our pipeline working again.
zip(...deletions2)
.pipe(
defaultIfEmpty([]),
tap((deletionResult) => console.log(deletionResult)),
switchMap(() => zip(...additions2)),
tap((additionResult) => console.log(additionResult)),
switchMap(() => zip(...edits2)),
tap((editsResult) => console.log(editsResult))
)
.subscribe();
Now our pipeline continues and values are logged to the console. The defaultIfEmpty([])
operator essentially says if the preceding observable doesn’t emit a value, emit an empty array and then continue on to the next step. So, although we don’t have anything to delete, we can still do our adds and edits.
Let’s look at one last example, where we have deletions and edits to do, but no additions. Can you guess what will happen?
const deletions3 = [of('delete3')];
const additions3 = [];
const edits3 = [of('edit 3')];
zip(...deletions3)
.pipe(
tap((deletionResult) => console.log(deletionResult)),
switchMap(() => zip(...additions3)),
tap((additionResult) => console.log(additionResult)),
switchMap(() => zip(...edits3)),
tap((editsResult) => console.log(editsResult))
)
.subscribe();
If you guessed nothing happens at all, you’re close. But it does finish the delete step before stopping. So your edits never occur. To fix the issue, we just need to add another defaultIfEmpty
operator.
zip(...deletions3)
.pipe(
tap((deletionResult) => console.log(deletionResult)),
switchMap(() => zip(...additions3).pipe(defaultIfEmpty([]))),
tap((additionResult) => console.log(additionResult)),
switchMap(() => zip(...edits3)),
tap((editsResult) => console.log(editsResult))
)
.subscribe();
Note: You can add the
defaultIfEmpty
operator in the pipe for the additions like I have above, or you can add it directly after theswitchMap
; either way will work.
With this minor change to our pipeline, it now finishes as we expect. The deletions are made, followed by the edits.
I was initially stuck with figuring out how to make sure my pipeline continued, even if there was an empty step in the pipeline. But I should have known there was an operator to help me out. There are a lot of operators, and while it makes RxJS seem overwhelming at first it’s also very convenient for situations like this. When you get stuck, ask for help and read the docs. You’re likely to find someone who’s run into the same problem and can point you in the right direction.
Here’s a StackBlitz with the examples we looked at above.
Original article source at: https://www.prestonlamb.com/
1670937608
The release of Vue 3 brought about substantial performance improvements, but they should not overshadow the introduction of new features and paradigms. In this article, Toptal Full-stack Developer Luka Mikec introduces you to the new Composition API and explains what Vue 3 means for code expressiveness, organization, and reuse.
Apart from admirable performance improvements, the recently released Vue 3 also brought several new features. Arguably the most important introduction is the Composition API. In the first part of this article, we recap the standard motivation for a new API: better code organization and reuse. In the second part, we will focus on less-discussed aspects of using the new API, such as implementing reactivity-based features that were inexpressible in Vue 2’s reactivity system.
We will refer to this as on-demand reactivity. After introducing the relevant new features, we will build a simple spreadsheet application to demonstrate the new expressiveness of Vue’s reactivity system. At the very end, we will discuss what real-world use this improvement on-demand reactivity might have.
Vue 3 is a major rewrite of Vue 2, introducing a plethora of improvements while retaining backward compatibility with the old API almost in its entirety.
One of the most significant new features in Vue 3 is the Composition API. Its introduction sparked much controversy when it was first discussed publicly. In case you are not already familiar with the new API, we will first describe the motivation behind it.
The usual unit of code organization is a JavaScript object whose keys represent various possible types of a piece of a component. Thus the object might have one section for reactive data (data
), another section for computed properties (computed
), one more for component methods (methods
), etc.
Under this paradigm, a component can have multiple unrelated or loosely related functionalities whose inner workings are distributed among the aforementioned component sections. For example, we might have a component for uploading files that implements two essentially separate functionalities: file management and a system that controls the upload status animation.
The <script>
portion might contain something like the following:
export default {
data () {
return {
animation_state: 'playing',
animation_duration: 10,
upload_filenames: [],
upload_params: {
target_directory: 'media',
visibility: 'private',
}
}
},
computed: {
long_animation () { return this.animation_duration > 5; },
upload_requested () { return this.upload_filenames.length > 0; },
},
...
}
There are benefits to this traditional approach to code organization, mainly in the developer not having to worry about where to write a new piece of code. If we’re adding a reactive variable, we insert it in the data
section. If we’re looking for an existing variable, we know it must be in the data
section.
This traditional approach of splitting the functionality’s implementation into sections (data
, computed
, etc.) is not suitable in all situations.
The following exceptions are cited often:
Vue 2 (and the backward-compatible Vue 3) offer a solution to most of the code organization and reuse issues: mixins.
Mixins allow the functionalities of a component to be extracted in a separate unit of code. Each functionality is put in a separate mixin and every component can use one or more mixins. Pieces defined in a mixin can be used in a component as if they were defined in the component itself. The mixins are a bit like classes in object-oriented languages in that they collect the code related to a given functionality. Like classes, mixins can be inherited (used) in other units of code.
However, reasoning with mixins is harder since, unlike classes, mixins need not be designed with encapsulation in mind. Mixins are allowed to be collections of loosely bound pieces of code without a well-defined interface to the outer world. Using more than one mixin at a time in the same component might result in a component that is difficult to comprehend and use.
Most object-oriented languages (e.g., C# and Java) discourage or even disallow multiple inheritance despite the fact that the object-oriented programming paradigm has the tools to deal with such complexity. (Some languages do allow multiple inheritance, such as C++, but composition is still preferred over inheritance.)
A more practical issue that may occur when using mixins in Vue is name collision, which occurs when using two or more mixins declaring common names. It should be noted here that if Vue’s default strategy for dealing with name collisions is not ideal in a given situation, the strategy can be adjusted by the developer.This comes at the cost of introducing more complexity.
Another issue is that mixins do not offer something akin to a class constructor. This is a problem because often we need functionality that is very similar, but not exactly the same, to be present in different components. This can be circumvented in some simple cases with the use of mixin factories.
Therefore, mixins are not the ideal solution for code organization and reuse, and the larger the project, the more serious their issues become. Vue 3 introduces a new way of solving the same issues concerning code organization and reuse.
The Composition API allows us (but does not require us) to completely decouple the pieces of a component. Every piece of code—a variable, a computed property, a watch, etc.—can be defined independently.
For example, instead of having an object that contains a data
section that contains a key animation_state
with the (default) value “playing,” we can now write (anywhere in our JavaScript code):
const animation_state = ref('playing');
The effect is almost the same as declaring this variable in the data
section of some component. The only essential difference is that we need to make the ref
defined outside of the component available in the component where we intend to use it. We do this by importing its module to the place where the component is defined and return the ref
from the setup
section of a component. We’ll skip this procedure for now and just focus on the new API for a moment. Reactivity in Vue 3 doesn’t require a component; it’s actually a self-contained system.
We can use the variable animation_state
in any scope that we import this variable to. After constructing a ref
, we get and set its actual value using ref.value
, for example:
animation_state.value = 'paused';
console.log(animation_state.value);
We need the ‘.value’ suffix since the assignment operator would otherwise assign the (non-reactive) value “paused” to the variable animation_state
. Reactivity in JavaScript (both when it is implemented through the defineProperty
as in Vue 2, and when it’s based on a Proxy
as in Vue 3) requires an object whose keys we can work with reactively.
Note that this was the case in Vue 2, as well; there, we had a component as a prefix to any reactive data member (component.data_member
). Unless and until the JavaScript language standard introduces the ability to overload the assignment operator, reactive expressions will require an object and a key (e.g., animation_state
and value
as above) to appear on the left-hand side of any assignment operation where we wish to preserve reactivity.
In templates, we can omit .value
since Vue has to preprocess the template code and can automatically detect references:
<animation :state='animation_state' />
In theory, the Vue compiler could preprocess the <script>
portion of a Single File Component (SFC) in a similar way, too, inserting .value
where needed. However, the use of refs
would then differ based on whether we are using SFCs or not, so perhaps such a feature is not even desirable.
Sometimes, we have an entity (for example, be a Javascript object or an array) that we never intend to replace with a completely different instance. Instead, we might only be interested in modifying its keyed fields. There is a shorthand in this case: using reactive
instead of ref
allows us to dispense with the .value
:
const upload_params = reactive({
target_directory: 'media',
visibility: 'private',
});
upload_params.visibility = 'public'; // no `.value` needed here
// if we did not make `upload_params` constant, the following code would compile but we would lose reactivity after the assignment; it is thus a good idea to make reactive variables ```const``` explicitly:
upload_params = {
target_directory: 'static',
visibility: 'public',
};
Decoupled reactivity with ref
and reactive
is not a completely new feature of Vue 3. It was partly introduced in Vue 2.6, where such decoupled instances of reactive data were called “observables.” For the most part, one can replace Vue.observable
with reactive
. One of the differences is that accessing and mutating the object passed to Vue.observable
directly is reactive, while the new API returns a proxy object, so mutating the original object will not have reactive effects.
What is completely new in Vue 3 is that other reactive pieces of a component can now be defined independently too, in addition to reactive data. Computed properties are implemented in an expected way:
const x = ref(5);
const x_squared = computed(() => x.value * x.value);
console.log(x_squared.value); // outputs 25
Similarly one can implement various types of watches, lifecycle methods, and dependency injection. For the sake of brevity, we won’t cover those here.
Suppose we use the standard SFC approach to Vue development. We might even be using the traditional API, with separate sections for data, computed properties, etc. How do we integrate the Composition API’s small bits of reactivity with SFCs? Vue 3 introduces another section just for this: setup
. The new section can be thought of as a new lifecycle method (which executes before any other hook—in particular, before created
).
Here is an example of a complete component that integrates the traditional approach with the Composition API:
<template>
<input v-model="x" />
<div>Squared: {{ x_squared }}, negative: {{ x_negative }}</div>
</template>
<script>
import { ref, computed } from 'vue';
export default {
name: "Demo",
computed: {
x_negative() { return -this.x; }
},
setup() {
const x = ref(0);
const x_squared = computed(() => x.value * x.value);
return {x, x_squared};
}
}
</script>
Things to take away from this example:
setup
. You might want to create a separate file for each functionality, import this file in an SFC, and return the desired bits of reactivity from setup
(to make them available to the remainder of the component).x
, even though it’s a reference, does not require .value
when referred to in the template code or in traditional sections of a component such as computed
.In the first part of this article, we touched upon the standard motivation for the Composition API, which is improved code organization and reuse. Indeed, the new API’s main selling point is not its power, but the organizational convenience that it brings: the ability to structure the code more clearly. It might seem like that is all—that the Composition API enables a way of implementing components that avoids the limitations of the already existing solutions, such as mixins.
However, there is more to the new API. The Composition API actually enables not just better organized but more powerful reactive systems. The key ingredient is the ability to dynamically add reactivity to the application. Previously, one had to define all the data, all the computed properties, etc. before loading a component. Why would adding reactive objects at a later stage be useful? In what remains we take a look at a more complex example: spreadsheets.
Spreadsheet tools such as Microsoft Excel, LibreOffice Calc, and Google Sheets all have some sort of a reactivity system. These tools present a user with a table, with columns indexed by A–Z, AA–ZZ, AAA–ZZZ, etc., and rows indexed numerically.
Each cell may contain a plain value or a formula. A cell with a formula is essentially a computed property, which may depend on values or other computed properties. With standard spreadsheets (and unlike the reactivity system in Vue), these computed properties are even allowed to depend on themselves! Such self-reference is useful in some scenarios where the desired value is obtained by iterative approximation.
Once a cell’s content changes, all the cells that depend on the cell in question will trigger an update. If further changes occur, further updates might be scheduled.
If we were to build a spreadsheet application with Vue, it would be natural to ask if we can put Vue’s own reactivity system to use and make Vue the engine of a spreadsheet app. For each cell, we could remember its raw editable value, as well as the corresponding computed value. Computed values would reflect the raw value if it’s a plain value, and otherwise, the computed values are the result of the expression (formula) that is written instead of a plain value.
With Vue 2, a way to implement a spreadsheet is to have raw_values
a two-dimensional array of strings, and computed_values
a (computed) two-dimensional array of cell values.
If the number of cells is small and fixed before the appropriate Vue component loads, we could have one raw and one computed value for every cell of the table in our component definition. Aside from the aesthetic monstrousness that such an implementation would cause, a table with a fixed number of cells at compile-time probably doesn’t count as a spreadsheet.
There are problems with the two-dimensional array computed_values
, too. A computed property is always a function whose evaluation, in this case, depends on itself (calculating the value of a cell will, in general, require some other values to already be computed). Even if Vue allowed self-referential computed properties, updating a single cell would cause all cells to be recomputed (regardless of whether there are dependencies or not). This would be extremely inefficient. Thus, we might end up using reactivity to detect changes in the raw data with Vue 2, but everything else reactivity-wise would have to be implemented from scratch.
With Vue 3, we can introduce a new computed property for every cell. If the table grows, new computed properties are introduced.
Suppose we have cells A1
and A2
, and we wish for A2
to display the square of A1
whose value is the number 5. A sketch of this situation:
let A1 = computed(() => 5);
let A2 = computed(() => A1.value * A1.value);
console.log(A2.value); // outputs 25
Suppose we stay in this simple scenario for a moment. There is an issue here; what if we wish to change A1
so that it contains the number 6? Suppose we write this:
A1 = computed(() => 6);
console.log(A2.value); // outputs 25 if we already ran the code above
This didn’t merely change the value 5 to 6 in A1
. The variable A1
has a completely different identity now: the computed property that resolves to the number 6. However, the variable A2
still reacts to changes of the old identity of the variable A1
. So, A2
shouldn’t refer to A1
directly, but rather to some special object that will always be available in the context, and will tell us what is A1
at the moment. In other words, we need a level of indirection before accessing A1
, something like a pointer. There are no pointers as first-class entities in Javascript, but it’s easy to simulate one. If we wish to have a pointer
pointing to a value
, we can create an object pointer = {points_to: value}
. Redirecting the pointer amounts to assigning to pointer.points_to
, and dereferencing (accessing the pointed-to value) amounts to retrieving the value of pointer.points_to
. In our case we proceed as follows:
let A1 = reactive({points_to: computed(() => 5)});
let A2 = reactive({points_to: computed(() => A1.points_to * A1.points_to)});
console.log(A2.points_to); // outputs 25
Now we can substitute 5 with 6.
A1.points_to = computed(() => 6);
console.log(A2.points_to); // outputs 36
On Vue’s Discord server, the user redblobgames suggested another interesting approach: instead of using computed values, use references that wrap regular functions. This way, one can similarly swap the function without changing the identity of the reference itself.
Our spreadsheet implementation will have cells referred to by keys of some two-dimensional array. This array can provide the level of indirection we require. Thus in our case, we won’t require any additional pointer simulation. We could even have one array that does not distinguish between raw and computed values. Everything can be a computed value:
const cells = reactive([
computed(() => 5),
computed(() => cells[0].value * cells[0].value)
]);
cells[0] = computed(() => 6);
console.log(cells[1].value); // outputs 36
However, we really want to distinguish raw and computed values since we want to be able to bind the raw value to an HTML input element. Furthermore, if we have a separate array for raw values, we never have to change the definitions of computed properties; they will update automatically based on the raw data.
Let’s start with some basic definitions, which are for the most part self-explanatory.
const rows = ref(30), cols = ref(26);
/* if a string codes a number, return the number, else return a string */
const as_number = raw_cell => /^[0-9]+(\.[0-9]+)?$/.test(raw_cell)
? Number.parseFloat(raw_cell) : raw_cell;
const make_table = (val = '', _rows = rows.value, _cols = cols.value) =>
Array(_rows).fill(null).map(() => Array(_cols).fill(val));
const raw_values = reactive(make_table('', rows.value, cols.value));
const computed_values = reactive(make_table(undefined, rows.value, cols.value));
/* a useful metric for debugging: how many times did cell (re)computations occur? */
const calculations = ref(0);
The plan is for every computed_values[row][column]
to be computed as follows. If raw_values[row][column]
doesn’t start with =
, return raw_values[row][column]
. Otherwise, parse the formula, compile it to JavaScript, evaluate the compiled code, and return the value. To keep things short, we’ll cheat a bit with parsing formulas and we won’t do some obvious optimizations here, such as a compilation cache.
We will assume that users can enter any valid JavaScript expression as a formula. We can replace references to cell names that appear in user’s expressions, such as A1, B5, etc., with the reference to the actual cell value (computed). The following function does this job, assuming that strings resembling cell names really always identify cells (and are not a part of some unrelated JavaScript expression). For simplicity, we will assume column indices consist of a single letter.
const letters = Array(26).fill(0)
.map((_, i) => String.fromCharCode("A".charCodeAt(0) + i));
const transpile = str => {
let cell_replacer = (match, prepend, col, row) => {
col = letters.indexOf(col);
row = Number.parseInt(row) - 1;
return prepend + ` computed_values[${row}][${col}].value `;
};
return str.replace(/(^|[^A-Z])([A-Z])([0-9]+)/g, cell_replacer);
};
Using the transpile
function, we can get pure JavaScript expressions out of expressions written in our little “extension” of JavaScript with cell references.
The next step is to generate computed properties for every cell. This procedure will occur once in the lifetime of every cell. We can make a factory that will return the desired computed properties:
const computed_cell_generator = (i, j) => {
const computed_cell = computed(() => {
// we don't want Vue to think that the value of a computed_cell depends on the value of `calculations`
nextTick(() => ++calculations.value);
let raw_cell = raw_values[i][j].trim();
if (!raw_cell || raw_cell[0] != '=')
return as_number(raw_cell);
let user_code = raw_cell.substring(1);
let code = transpile(user_code);
try {
// the constructor of a Function receives the body of a function as a string
let fn = new Function(['computed_values'], `return ${code};`);
return fn(computed_values);
} catch (e) {
return "ERROR";
}
});
return computed_cell;
};
for (let i = 0; i < rows.value; ++i)
for (let j = 0; j < cols.value; ++j)
computed_values[i][j] = computed_cell_generator(i, j);
If we put all of the code above in the setup
method, we need to return {raw_values, computed_values, rows, cols, letters, calculations}
.
Below, we present the complete component, together with a basic user interface.
The code is available on GitHub, and you can also check out the live demo.
<template>
<div>
<div style="margin: 1ex;">Calculations: {{ calculations }}</div>
<table class="table" border="0">
<tr class="row">
<td id="empty_first_cell"></td>
<td class="column"
v-for="(_, j) in cols" :key="'header' + j"
>
{{ letters[j] }}
</td>
</tr>
<tr class="row"
v-for="(_, i) in rows" :key="i"
>
<td class="column">
{{ i + 1 }}
</td>
<td class="column"
v-for="(__, j) in cols" :key="i + '-' + j"
:class="{ column_selected: active(i, j), column_inactive: !active(i, j), }"
@click="activate(i, j)"
>
<div v-if="active(i, j)">
<input :ref="'input' + i + '-' + j"
v-model="raw_values[i][j]"
@keydown.enter.prevent="ui_enter()"
@keydown.esc="ui_esc()"
/>
</div>
<div v-else v-html="computed_value_formatter(computed_values[i][j].value)"/>
</td>
</tr>
</table>
</div>
</template>
<script>
import {ref, reactive, computed, watchEffect, toRefs, nextTick, onUpdated} from "vue";
export default {
name: 'App',
components: {},
data() {
return {
ui_editing_i: null,
ui_editing_j: null,
}
},
methods: {
get_dom_input(i, j) {
return this.$refs['input' + i + '-' + j];
},
activate(i, j) {
this.ui_editing_i = i;
this.ui_editing_j = j;
nextTick(() => this.get_dom_input(i, j).focus());
},
active(i, j) {
return this.ui_editing_i === i && this.ui_editing_j === j;
},
unselect() {
this.ui_editing_i = null;
this.ui_editing_j = null;
},
computed_value_formatter(str) {
if (str === undefined || str === null)
return 'none';
return str;
},
ui_enter() {
if (this.ui_editing_i < this.rows - 1)
this.activate(this.ui_editing_i + 1, this.ui_editing_j);
else
this.unselect();
},
ui_esc() {
this.unselect();
},
},
setup() {
/*** All the code we wrote above goes here. ***/
return {raw_values, computed_values, rows, cols, letters, calculations};
},
}
</script>
<style>
.table {
margin-left: auto;
margin-right: auto;
margin-top: 1ex;
border-collapse: collapse;
}
.column {
box-sizing: border-box;
border: 1px lightgray solid;
}
.column:first-child {
background: #f6f6f6;
min-width: 3em;
}
.column:not(:first-child) {
min-width: 4em;
}
.row:first-child {
background: #f6f6f6;
}
#empty_first_cell {
background: white;
}
.column_selected {
border: 2px cornflowerblue solid !important;
padding: 0px;
}
.column_selected input, .column_selected input:active, .column_selected input:focus {
outline: none;
border: none;
}
</style>
We saw how the decoupled reactivity system of Vue 3 enables not only cleaner code but allows more complex reactive systems based on the Vue’s new reactivity mechanism. Roughly seven years have passed since Vue was introduced, and the rise in expressiveness was clearly not highly sought after.
The spreadsheet example is a straightforward demonstration of what Vue is capable of now, and you can also check out the live demo.
But as a real-word example, it is somewhat niche. In what sort of situations might the new system come in handy? The most obvious use-case for on-demand reactivity might be in performance gains for complex applications.
In front-end applications that work with a large amount of data, the overhead of using poorly thought-through reactivity might have a negative impact on performance. Suppose we have a business dashboard application that produces interactive reports of the company’s business activity. The user can select a time range and add or remove performance indicators in the report. Some indicators may display values that depend on other indicators.
One way to implement report generation is through a monolithic structure. When the user changes an input parameter in the interface, a single computed property, e.g., report_data
, gets updated. The computation of this computed property happens according to a hardcoded plan: first, calculate all the independent performance indicators, then those that depend only on these independent indicators, etc.
A better implementation will decouple bits of the report and compute them independently. There are some benefits to this:
If all performance indicators that may be a part of the final report are known before the Vue component gets loaded, we may be able to implement the proposed decoupling even with Vue 2. Otherwise, if the backend is the single source of truth (which is usually the case with data-driven applications), or if there are external data providers, we can generate on-demand computed properties for every piece of a report.
Thanks to Vue 3, this is now not only possible but easy to do.
Original article source at: https://www.toptal.com/
1666950180
A protocol to enable UIViewController
s or UIView
s to present placeholder views based on content, loading, error or empty states.
In a networked application a view controller or custom view typically has the following states that need to be communicated to the user:
As trivial as this flow may sound, there are a lot of cases that result in a rather large decision tree.
StatefulViewController
is a concrete implementation of this particular decision tree. (If you want to create your own modified version, you might be interested in the state machine that is used to show and hide views.)
Current Swift compatibility breakdown:
Swift Version | Framework Version |
---|---|
3.0 | 3.x |
2.3 | 2.x |
2.2 | 1.x |
This guide describes the use of the
StatefulViewController
protocol onUIViewController
. However, you can also adopt theStatefulViewController
protocol on anyUIViewController
subclass, such asUITableViewController
orUICollectionViewController
, as well as your customUIView
subclasses.
First, make sure your view controller adopts to the StatefulViewController
protocol.
class MyViewController: UIViewController, StatefulViewController {
// ...
}
Then, configure the loadingView
, emptyView
and errorView
properties (provided by the StatefulViewController
protocol) in viewDidLoad
.
override func viewDidLoad() {
super.viewDidLoad()
// Setup placeholder views
loadingView = // UIView
emptyView = // UIView
errorView = // UIView
}
In addition, call the setupInitialViewState()
method in viewWillAppear:
in order to setup the initial state of the controller.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
setupInitialViewState()
}
After that, simply tell the view controller whenever content is loading and StatefulViewController
will take care of showing and hiding the correct loading, error and empty view for you.
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
loadDeliciousWines()
}
func loadDeliciousWines() {
startLoading()
let url = NSURL(string: "http://example.com/api")
let session = NSURLSession.sharedSession()
session.dataTaskWithURL(url) { (let data, let response, let error) in
endLoading(error: error)
}.resume()
}
StatefulViewController calls the hasContent
method to check if there is any content to display. If you do not override this method in your own class, StatefulViewController
will always assume that there is content to display.
func hasContent() -> Bool {
return datasourceArray.count > 0
}
Optionally, you might also be interested to respond to an error even if content is already shown. StatefulViewController
will not show its errorView
in this case, because there is already content that can be shown.
To e.g. show a custom alert or other unobtrusive error message, use handleErrorWhenContentAvailable:
to manually present the error to the user.
func handleErrorWhenContentAvailable(error: ErrorType) {
let alertController = UIAlertController(title: "Ooops", message: "Something went wrong.", preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
presentViewController(alertController, animated: true, completion: nil)
}
Per default, StatefulViewController presents all configured placeholder views fullscreen (i.e. with 0 insets from top, bottom, left & right from the superview). In case a placeholder view should have custom insets the configured placeholderview may conform to the StatefulPlaceholderView
protocol and override the placeholderViewInsets
method to return custom edge insets.
class MyPlaceholderView: UIView, StatefulPlaceholderView {
func placeholderViewInsets() -> UIEdgeInsets {
return UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
}
}
Note: The following section is only intended for those, who want to create a stateful controller that differs from the flow described above.
You can also use the underlying view state machine to create a similar implementation for your custom flow of showing/hiding views.
let stateMachine = ViewStateMachine(view: view)
// Add states
stateMachine["loading"] = loadingView
stateMachine["other"] = otherView
// Transition to state
stateMachine.transitionToState(.View("loading"), animated: true) {
println("finished switching to loading view")
}
// Hide all views
stateMachine.transitionToState(.None, animated: true) {
println("all views hidden now")
}
Add the following line to your Cartfile.
github "aschuch/StatefulViewController" ~> 3.0
Then run carthage update
.
Add the following line to your Podfile.
pod "StatefulViewController", "~> 3.0"
Then run pod install
with CocoaPods 0.36 or newer.
Just drag and drop the two .swift
files in the StatefulViewController
folder into your project.
Open the Xcode project and press ⌘-U
to run the tests.
Alternatively, all tests can be run from the terminal using xctool.
xctool -scheme StatefulViewControllerTests -sdk iphonesimulator test
Feel free to get in touch.
Author: Aschuch
Source Code: https://github.com/aschuch/StatefulViewController
License: MIT license
1661872140
julia> using Postgres
julia> conn = connect(PostgresServer, db="julia_test", host="localhost")
julia> #conn = connect(PostgresServer, "postgresql://localhost/julia_test")
julia> #empty strings will cause the server to use defaults.
julia> #connect(interface, user, db, host, passwd, port)
julia> #conn = connect(PostgresServer, "", "julia_test", "localhost", "", "")
julia> curs = cursor(conn)
julia> df = query(curs, "select 1 from generate_series(1,5) as s")
5x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
Memory management is automatic for the cursor interface.
julia> execute(curs, "select 1 from generate_series(1, 10)")
julia> for res in curs; println(res); end;
10x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
| 4 | 1 |
| 5 | 1 |
| 6 | 1 |
| 7 | 1 |
| 8 | 1 |
| 9 | 1 |
| 10 | 1 |
julia> for res in curs; println(res); end;
# nothing (memory already freed from server)
julia> streamed = cursor(conn, 3)
julia> execute(streamed, "select 1 from generate_series(1, 10)")
julia> for res in streamed; println(res); end;
3x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
3x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
3x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
1x1 DataFrames.DataFrame
| Row | x1 |
|-----|----|
| 1 | 1 |
0x1 DataFrames.DataFrame
Each iteration allocs and frees memory.
Cursor must be closed (or unreachable) to release server resources.
julia> using Postgres.Results
julia> result = execute(curs, "select 1, null::int, 'HI'::text, 1.2::float8
from generate_series(1, 5)")
5x4{Int32, Int32, UTF8String, Float64} PostgresResult
julia> result[1,1] # array
Nullable(1)
julia> result[1, :] # row; also row(curs, 1)
4-element Array{Any,1}:
Nullable(1)
Nullable{Int32}()
Nullable("HI")
Nullable(1.2)
# columns are a lot faster to create
julia> result[:, 1] # columns; also column(curs, 1)
5-element DataArrays.DataArray{Int32,1}:
1
1
1
1
1
#row iteration
julia> for row in result; println(row); end
Any[Nullable(1),Nullable{Int32}(),Nullable("HI"),Nullable(1.2)]
# ...
close(curs) # free postgres resources
julia> begin_!(curs)
INFO: BEGIN
julia> rollback!(curs)
INFO: ROLLBACK
julia> commit!(curs)
WARNING: WARNING: there is no transaction in progress
INFO: COMMIT
# transaction already ended by rollback
julia> for v in values(Postgres.Types.base_types)
println(v)
end
text -> UTF8String
varchar -> UTF8String
bpchar -> UTF8String
unknown -> UTF8String
bit -> BitArray{1}
varbit -> BitArray{1}
bytea -> Array{UInt8,1}
bool -> Bool
int2 -> Int16
int4 -> Int32
int8 -> Int64
float4 -> Float32
float8 -> Float64
numeric -> BigFloat
date -> Date
json -> UTF8String
jsonb -> UTF8String
Others supported as UTF8String.
Automatically determined on connection start up.
julia> types = collect(values(conn.pgtypes))
julia> enum_test = filter(x->x.name==:enum_test, types)[1]
enum_test ∈ Set(UTF8String["happy","sad"])
# pg def:
# Schema │ Name │ Internal name │ Size │ Elements │
#────────┼───────────┼───────────────┼──────┼──────────┼
# public │ enum_test │ enum_test │ 4 │ happy ↵│
# │ │ │ │ sad │
julia> domain_test = filter(x->x.name==:domain_test, types)[1]
(domain_test <: int4) -> Int32
# pg def:
# Schema │ Name │ Type │ Modifier │ Check │
#────────┼─────────────┼─────────┼──────────┼────────────────────────────────────┼
# public │ domain_test │ integer │ │ CHECK (VALUE >= 0 AND VALUE <= 10) │
Enum types will use PooledDataArrays!
julia> user_input="1';select 'powned';"
julia> escape_value(conn, user_input)
"'1'';select ''powned'';'"
julia> try query(curs, "select xxx")
catch err PostgresServerError
println(err.info)
end
PostgresResultInfo(
msg:ERROR: column "xxx" does not exist
LINE 1: select xxx
^
severity:ERROR
state:syntax_error_or_access_rule_violation
code:42703
primary:column "xxx" does not exist
detail:
hint:
pos:8
)
see Appendix A. in the Postgres manual for error code/state lists.
# Commands use the same interface as selects.
# Messages are passed through to Julia as you are used to seeing them in psql.
julia> println(query(curs, """
drop table if exists s;
drop table if exists news;
create table s as select 1 as ss from generate_series(1,10)"""))
NOTICE: table "news" does not exist, skipping
INFO: SELECT 10 10
0x0 DataFrames.DataFrame
julia> df = query(curs, "select * from s")
julia> copyto(curs, df, "s")
INFO: COPY 10 10
0x0{} PostgresResult
julia> copyto(curs, df, "news", true)
INFO: table 'news' not found in database. creating ...
INFO: CREATE TABLE
INFO: COPY 10 10
0x0{} PostgresResult
julia> using Postgres.Types
julia> type Point
x::Float64
y::Float64
end
# find the oid (600 in this case) in the pg_type table in Postgres.
# Then instance the type.
julia> base_types[600] = PostgresType{Point}(:point, Point(0, 0))
point -> Point
# create the _in_ function from the database
julia> function Postgres.Types.unsafe_parse{T <: Point}(::PostgresType{T}, value::UTF8String)
x, y = split(value, ",")
x = parse(Float64, x[2:end])
y = parse(Float64, y[1:end-1])
Point(x, y)
end
unsafe_parse (generic function with 15 methods)
# create the _out_ function to the database
julia> Postgres.Types.PostgresValue{T <: Point}(val::T) =
Postgres.Types.PostgresValue{T}(base_types[600], "($(val.x),$(val.y))")
Postgres.Types.PostgresValue
#reload conn so it picks up the new type
julia> close(conn)
PostgresConnection(@ 0 : not_connected)
julia> conn = connect(PostgresServer, db="julia_test", host="localhost")
PostgresConnection(@ 0x0b41b818 : ok)
julia> curs = cursor(conn)
Postgres.BufferedPostgresCursor(
PostgresConnection(@ 0x0b41b818 : ok),
Nullable{Postgres.Results.PostgresResult}())
julia> p1 = Point(1.1, 1.1)
Point(1.1,1.1)
julia> start = repr(PostgresValue(p1))
"'(1.1,1.1)'::point"
julia> p2 = query(curs, "select $start")[1][1]
Point(1.1,1.1)
julia> p1.x == p2.x && p1.y == p2.y
true
julia> query(curs, "select 1 from generate_series(1, (10^9)::int)")
# oops; this will take forever
^CINFO: canceling statement due to user request
ERROR: PostgresError: No results to fetch
in fetch at /home/xxx/.julia/v0.4/Postgres/src/postgres.jl:383
in query at /home/xxx/.julia/v0.4/Postgres/src/postgres.jl:405
#no need to chase down zombie process with ps or top :) :)
Author: NCarson
Source Code: https://github.com/NCarson/Postgres.jl
License: View license
1657221960
Create a temporary sublevel that is guaranteed to be empty.
npm install level-temp
var temp = require('level-temp')
var tmp = temp(db) // where db is a levelup
// call tmp to get a temporary sublevel that is empty
var a = tmp()
a.put('hello', 'world', function () {
a.createReadStream()
.on('data', function (data) {
console.log('a has only one', data)
})
})
// call tmp again to get another empty sublevel
var b = tmp()
b.put('hej', 'verden', function () {
b.createReadStream()
.on('data', function (data) {
console.log('b has only one', data)
})
})
If you explicitly close the tmp database (using tmpDb.close()
) the contents will be removed. If you restart your application previous tmp data will be overriden as well.
tmp = temp(db, [options])
Create a new temporary sublevel generator. Options are used as default for any tmp databases created afterwards. Optionally you can set prefix
to a string that will prefix all tmp sublevels created.
var tmp = temp(db, {valueEncoding: 'json'}) // set valueEncoding: json all tmp sublevels
var tmpDb = tmp([options])
Create a new temporary sublevel.
Any options
passed here are forwarded to levelup with the default values from the temp
constructor mixed in.
Per default an increasing number is used to prefix the temporary sublevels. To change this set the prefix
to whatever string you want to use as a prefix.
The returned tmpDb
is a regular levelup that will have its contents garbage collected when you call tmpDb.close()
or at some point in the future when the temporary sublevel prefix is being reused.
Author: Mafintosh
Source Code: https://github.com/mafintosh/level-temp
License: MIT license
1652493960
Linux用のあまり知られていないユーティリティとコマンドの別のリストが戻ってきました。これはあなたが日常の仕事をより速く進めるのに役立ちます。
私たちは、ブラウザのグラフィカルインターフェイスを介してGoogle検索を使用することに慣れています。ただし、これは、グラフィカルインターフェイスが使用できない環境では問題になります。googlerユーティリティを使用すると、コマンドラインからGoogle検索を実行できるようになります。
Googlerは、Linuxターミナル内でGoogle(Web&News&Search)にアクセスするためのフル機能のPythonベースのコマンドラインツールです。
URL:https ://github.com/jarun/googler
インストール方法:
# ubuntu$ sudo add-apt-repository ppa:twodopeshaggy/jarun
$ sudo apt-get update
$ sudo apt install googlerOR$ sudo snap install googler
使用例:
$ googler ford usa
グーグル実行中
コマンド「ls」を入力する代わりに、「sl」と入力した頻度はどれくらいですか。
面倒な「コマンドが見つかりません」というメッセージを表示する代わりに、この小さなユーティリティは素敵な画像を表示します。少なくともこのように、あなたは少し笑うか、次回はもっと注意するでしょう。
インストール方法:
$sudo apt install sl
使用例:
$ sl
slランニング
確かに、注意を引くのにも役立ちますが、最終的には面倒になる可能性があります。
hstrは私が毎日使用している優れたツールで、シェル履歴の提案ボックスに入力されたコマンドの履歴を簡単に表示、参照、検索できます。bashとzshで使用できます。
URL:http ://dvorka.github.io/hstr/
URL:https ://github.com/dvorka/hstr
インストール方法:
#Ubuntu
$ sudo add-apt-repository ppa:ultradvorka/ppa && sudo apt-get update && sudo apt-get install hstr && hstr --show-configuration >> ~/.bashrc && . ~/.bashrc
Linuxにデフォルトで付属しているこのコマンドは、事前定義された応答を端末に渡すために使用できるシステム管理者にとって便利です。
使用例:
$ yes hello-world
はい実行中
与えられたすべての文字列を逆にします。これは時々役に立ちます。
使用例:
$ rev
$ hello world!
revrunning
良いことは、何もインストールする必要がないことです。
このLinuxユーティリティは、コマンドラインからウィキペディアの記事を検索するために使用されます。
使用する必要があるのは、情報を取得する検索語を使用してコマンドを実行することだけです。
URL:https ://www.tecmint.com/wikipedia-commandline-tool/
インストール方法:
# Debian/Ubuntu$ sudo apt install nodejs $ sudo npm install wikit -g
使用例:
Wikit matrix
ウィキの実行
このツールは、「df」コマンドの優れた代替手段です。Linuxファイルシステムで使用されているディスク容量と使用可能なディスク容量がdfコマンドと同じように表示されますが、色が異なり、結果をカスタマイズすることもできます。
Pythonで書かれていることに注意してください。
URL:https ://pypi.org/project/pydf/
#Ubuntu# only if you do not have phyton installed:
$ sudo apt install python3-pip
$ pip install pydf
実行中のpydf
Trash-cliは、ファイルをゴミ箱に移動し、元の絶対パス、削除日、およびアクセス許可を記録するコマンドラインインターフェイスです。
URL:https://github.com/andreafrancia/trash-cli
インストール方法:
# Debian/Ubuntu systems
$ sudo easy_install trash-cli
使用例:
# We create an example file named file1
$ echo "hello world!" > file1
$ trash-put file1
#
$ trash-list
使用可能なコマンド:
$ trash-put #trash files and directories.
$ trash-list #list trashed files.
$ trash-restore #restore a trashed file.
$ trash-rm #remove individual files from the trashcan.
$ trash-empty #empty the trashcan(s).
trash-cliの実行
eSpeak NGは、英語やその他の言語でテキストを音声に変換するために使用できる無料のオープンソースソフトウェアです。これは、JonathanDuddingtonによって作成されたeSpeakエンジンに基づいています。
URL: https://github.com/espeak-ng/espeak-ng
インストール方法:
# Ubuntu
$ apt-get install espeak
それでは、「こんにちはケスク!」というセリフを話しましょう。そしてそれをhello.mp4オーディオファイルに録音します:
$ espeak "Hi Kesk!" -w hello.mp4 -g 60 -p 70 -s 100 -v en-us
録音したいテキストファイルを指定することもできます。
$ espeak -f example.txt -w example.mp4 -g 60 -p 70 -s 100 -v en-us
今、あなたがしなければならないのはあなたの好きなアプリケーションでそれをプレイすることだけです、そしてそれはそれです。
このコマンドラインシステム監視ユーティリティを使用すると、CPU、負荷平均、メモリ、ネットワークインターフェイス、ディスクI / O、プロセス、およびファイルシステムスペースの使用率を監視できます。
GlancesユーティリティはPythonで記述されており、psutilライブラリを使用してシステム情報を取得し、わかりやすい形式で表示します。
また、構成ファイルを使用してさまざまな警告しきい値を設定することもできます。
すべてを管理するのに非常に便利です。
URL:https ://nicolargo.github.io/glances/
インストール方法:
$ sudo apt install glances
使用例:
$ glances
走っている一瞥
gtopユーティリティは、システムとそのプロセスに関するさまざまな情報を表示するLinuxシステムモニターです。
このツールは使いやすく、リソースをほとんど消費しないため、リソースを無駄にすることなく実行できます。さらに、オペレーティングシステムのコマンドを使用するため、非常に印象的で正確な方法で情報を表示します。
これは、CanGüneyAksakalliによってJavaScriptで開発されたオープンソースツールであり、インストールして実行するには、コンピューターにnodejsをインストールする必要があります。
URL:git clone https://github.com/aksakalli/gtop.git
インストール方法:
$ sudo npm install gtop -g
使用例:
$ gtop
gtopランニング
以前のユーティリティと同様に、この小さなプログラムはデフォルトであり、ある時点で役立つ場合があります。
ファクターランニング
Linuxのコマンドラインユーティリティや、特に役立つコマンドやあまり知られていないコマンドをご存知の場合は、それについて教えていただければ幸いです。
ありがとうございました!
ソース:https ://medium.com/codex/12-awesome-linux-commands-utilities-49ab56588a84
1652493840
Vuelvo con otra lista de utilidades y comandos poco conocidos para Linux que te ayudarán a ir más rápido con tu trabajo diario.
Estamos acostumbrados a utilizar la búsqueda de Google a través de una interfaz gráfica en el navegador. Sin embargo, esto es un problema en entornos donde la interfaz gráfica no está disponible. Con la utilidad googler podremos realizar búsquedas en Google desde la línea de comandos.
Googler es una herramienta de línea de comandos basada en Python con todas las funciones para acceder a Google (Web & News & Search) dentro de la terminal de Linux.
URL: https://github.com/jarun/googler
Cómo instalarlo:
# ubuntu$ sudo add-apt-repository ppa:twodopeshaggy/jarun
$ sudo apt-get update
$ sudo apt install googlerOR$ sudo snap install googler
Ejemplo de uso:
$ googler ford usa
google corriendo
En lugar de escribir el comando 'ls', ¿con qué frecuencia ha escrito 'sl'?
En lugar de mostrarte el tedioso mensaje de "comando no encontrado", esta pequeña utilidad te mostrará una bonita imagen; al menos así te reirás un poco o tendrás más cuidado la próxima vez.
Cómo instalarlo:
$sudo apt install sl
Ejemplo de uso:
$ sl
sl corriendo
Es cierto que al final puede resultar cansino, aunque también servirá para que prestes atención.
hstr es una gran herramienta que uso a diario que le permite ver, explorar y buscar fácilmente el historial de comandos ingresados en el cuadro de sugerencias del historial de shell. Está disponible para bash y zsh.
URL: http://dvorka.github.io/hstr/
URL: https://github.com/dvorka/hstr
Cómo instalarlo:
#Ubuntu
$ sudo add-apt-repository ppa:ultradvorka/ppa && sudo apt-get update && sudo apt-get install hstr && hstr --show-configuration >> ~/.bashrc && . ~/.bashrc
Este comando que viene por defecto en Linux es útil para los administradores de sistemas que pueden usarlo para pasar una respuesta predefinida a la terminal.
Ejemplo de uso:
$ yes hello-world
si corriendo
Invierte cada cadena que se le da, lo que a veces es útil.
Ejemplo de uso:
$ rev
$ hello world!
revoluciones corriendo
Lo bueno es que no tienes que instalar nada.
Esta utilidad de Linux se utiliza para buscar artículos de Wikipedia desde la línea de comandos.
Lo único que tienes que hacer para usar es ejecutar el comando con el término de búsqueda que deseas obtener la información.
URL: https://www.tecmint.com/wikipedia-commandline-tool/
Cómo instalarlo:
# Debian/Ubuntu$ sudo apt install nodejs $ sudo npm install wikit -g
Ejemplo de uso:
Wikit matrix
corriendo
Esta herramienta es una excelente alternativa al comando “df”. Muestra la cantidad de espacio en disco utilizado y disponible en un sistema de archivos de Linux, al igual que el comando df, pero con diferentes colores, y también le permite personalizar los resultados.
Tenga en cuenta que está escrito en Python.
URL: https://pypi.org/project/pydf/
#Ubuntu# only if you do not have phyton installed:
$ sudo apt install python3-pip
$ pip install pydf
pdf ejecutando
Trash-cli es una interfaz de línea de comandos que desecha archivos y registra la ruta absoluta original, la fecha de eliminación y los permisos.
URL: https://github.com/andreafrancia/trash-cli
Cómo instalarlo:
# Debian/Ubuntu systems
$ sudo easy_install trash-cli
Ejemplo de uso:
# We create an example file named file1
$ echo "hello world!" > file1
$ trash-put file1
#
$ trash-list
Comandos disponibles:
$ trash-put #trash files and directories.
$ trash-list #list trashed files.
$ trash-restore #restore a trashed file.
$ trash-rm #remove individual files from the trashcan.
$ trash-empty #empty the trashcan(s).
basura-cli corriendo
eSpeak NG es un software gratuito y de código abierto que se puede utilizar para convertir texto a voz en inglés y otros idiomas. Se basa en el motor eSpeak creado por Jonathan Duddington.
URL: https://github.com/espeak-ng/espeak-ng
Cómo instalarlo:
# Ubuntu
$ apt-get install espeak
Ahora, digamos la línea "¡Hola, Kesk!" y grábelo en el archivo de audio hello.mp4:
$ espeak "Hi Kesk!" -w hello.mp4 -g 60 -p 70 -s 100 -v en-us
También puede especificar el archivo de texto que desea grabar.
$ espeak -f example.txt -w example.mp4 -g 60 -p 70 -s 100 -v en-us
Ahora todo lo que tienes que hacer es jugarlo con tu aplicación favorita, y listo.
Esta utilidad de monitoreo del sistema de línea de comandos le permite monitorear la CPU, el promedio de carga, la memoria, las interfaces de red, la E/S del disco, los procesos y la utilización del espacio del sistema de archivos.
La utilidad Glances está escrita en Python y utiliza la biblioteca psutil para obtener información del sistema y mostrarla en un formato amigable.
También nos permite establecer diferentes umbrales de alerta mediante un archivo de configuración.
Muy útil para tenerlo todo bajo control.
URL: https://nicolargo.github.io/glances/
Cómo instalarlo:
$ sudo apt install glances
Ejemplo de uso:
$ glances
miradas corriendo
La utilidad gtop es un monitor del sistema Linux que muestra diversa información sobre el sistema y sus procesos.
La herramienta es fácil de usar y consume muy pocos recursos, por lo que podemos tenerla funcionando sin gastar recursos. Además, muestra la información de una forma bastante llamativa y precisa ya que utiliza comandos del sistema operativo.
Es una herramienta de código abierto desarrollada en JavaScript por Can Güney Aksakalli, y necesitará tener instalado nodejs en su computadora para instalarlo y ejecutarlo.
URL: clon de git https://github.com/aksakalli/gtop.git
Cómo instalarlo:
$ sudo npm install gtop -g
Ejemplo de uso:
$ gtop
corriendo
Al igual que la utilidad anterior, este pequeño programa viene por defecto y puede ser de ayuda en algún momento.
funcionamiento del factor
Si conoces alguna utilidad de línea de comandos de Linux o algún comando que te ayude especialmente y no sea muy conocido, te agradecería que nos lo comentaras.
¡Gracias!
Fuente: https://medium.com/codex/12-awesome-linux-commands-utilities-49ab56588a84
1621315249
https://phpcoder.tech/isset-vs-empty-vs-is_null-in-php-with-example/
#isset #empty #is_null #php #difference
1617078772
In this example i will show you how to check array is empty or null in JavaScript or jQuery. When we are working in java script and you want to loop the array that time we need to check whether array is empty or not, so it doesn’t return error.
There are many ways to check Java script array is empty or not so I will give you some examples.
Thanks for the reading…!!
#javascript #jquery #php #array #empty #null
1590570452
In this tutorial, we will learn how to Empty an Array in JavaScript. You can simply use the array's length property to empty an array in JavaScript.
Example:
var arr1 = [1,2,3,4,5];
// Reference arr1 by another variable
var arr2 = arr1;
// Making arr1 empty
arr1.length = 0;
console.log(arr1.length); // Prints: 0
console.log(arr2.length); // Prints: 0
You can alternatively use the square bracket notation to empty an array, such as arr1 = []
, if you don't have any references to the original array arr1
anywhere else in your code, because it creates a brand new empty array instead of emptying the original array, as you can see here:
Example:
var arr1 = [1,2,3,4,5];
// Reference arr1 by another variable
var arr2 = arr1;
// Making arr1 empty
arr1 = [];
console.log(arr1.length); // Prints: 0
console.log(arr2.length); // Prints: 5
#javascript #clear array #empty array #java